branch: externals/tramp commit 55df3a59a95656d6c99226c6b24eea72bf1706c5 Author: Michael Albinus <michael.albi...@gmx.de> Commit: Michael Albinus <michael.albi...@gmx.de>
Tramp ELPA version 2.4.2.2 released --- test/tramp-tests.el | 178 ++++++++++++++++++++++++++++----------- texi/tramp.texi | 112 ++++++++++++++----------- texi/trampver.texi | 2 +- tramp-adb.el | 198 +++++++++++++++++++++---------------------- tramp-cache.el | 25 +++++- tramp-compat.el | 49 ++++++++--- tramp-gvfs.el | 60 ++++++++++++-- tramp-loaddefs.el | 4 +- tramp-rclone.el | 13 +-- tramp-sh.el | 235 +++++++++++++++++++++++++--------------------------- tramp-smb.el | 29 +++---- tramp-sudoedit.el | 70 +++++++--------- tramp.el | 96 ++++++++++----------- tramp.info | 172 ++++++++++++++++++++------------------ trampver.el | 4 +- 15 files changed, 702 insertions(+), 545 deletions(-) diff --git a/test/tramp-tests.el b/test/tramp-tests.el index 8dbbb2c..1b1e2e7 100644 --- a/test/tramp-tests.el +++ b/test/tramp-tests.el @@ -56,6 +56,7 @@ (declare-function tramp-list-tramp-buffers "tramp-cmds") (declare-function tramp-method-out-of-band-p "tramp-sh") (declare-function tramp-smb-get-localname "tramp-smb") +(declare-function tramp-time-diff "tramp") (defvar auto-save-file-name-transforms) (defvar tramp-connection-properties) (defvar tramp-copy-size-limit) @@ -3006,22 +3007,28 @@ This tests also `access-file', `file-readable-p', ;; We do not test inodes and device numbers. (setq attr (file-attributes tmp-name1)) (should (consp attr)) - (should (null (car attr))) - (should (numberp (nth 1 attr))) ;; Link. - (should (numberp (nth 2 attr))) ;; Uid. - (should (numberp (nth 3 attr))) ;; Gid. - ;; Last access time. - (should (stringp (current-time-string (nth 4 attr)))) - ;; Last modification time. - (should (stringp (current-time-string (nth 5 attr)))) - ;; Last status change time. - (should (stringp (current-time-string (nth 6 attr)))) - (should (numberp (nth 7 attr))) ;; Size. - (should (stringp (nth 8 attr))) ;; Modes. + (should (null (tramp-compat-file-attribute-type attr))) + (should (numberp (tramp-compat-file-attribute-link-number attr))) + (should (numberp (tramp-compat-file-attribute-user-id attr))) + (should (numberp (tramp-compat-file-attribute-group-id attr))) + (should + (stringp + (current-time-string + (tramp-compat-file-attribute-access-time attr)))) + (should + (stringp + (current-time-string + (tramp-compat-file-attribute-modification-time attr)))) + (should + (stringp + (current-time-string + (tramp-compat-file-attribute-status-change-time attr)))) + (should (numberp (tramp-compat-file-attribute-size attr))) + (should (stringp (tramp-compat-file-attribute-modes attr))) (setq attr (file-attributes tmp-name1 'string)) - (should (stringp (nth 2 attr))) ;; Uid. - (should (stringp (nth 3 attr))) ;; Gid. + (should (stringp (tramp-compat-file-attribute-user-id attr))) + (should (stringp (tramp-compat-file-attribute-group-id attr))) (tramp--test-ignore-make-symbolic-link-error (should-error @@ -3040,7 +3047,7 @@ This tests also `access-file', `file-readable-p', (string-equal (funcall (if quoted #'tramp-compat-file-name-quote #'identity) - (car attr)) + (tramp-compat-file-attribute-type attr)) (file-remote-p (file-truename tmp-name1) 'localname))) (delete-file tmp-name2)) @@ -3059,7 +3066,7 @@ This tests also `access-file', `file-readable-p', (setq attr (file-attributes tmp-name2)) (should (string-equal - (car attr) + (tramp-compat-file-attribute-type attr) (tramp-file-name-localname (tramp-dissect-file-name tmp-name3)))) (delete-file tmp-name2)) @@ -3075,19 +3082,79 @@ This tests also `access-file', `file-readable-p', (when (tramp--test-sh-p) (should (file-ownership-preserved-p tmp-name1 'group))) (setq attr (file-attributes tmp-name1)) - (should (eq (car attr) t))) + (should (eq (tramp-compat-file-attribute-type attr) t))) ;; Cleanup. (ignore-errors (delete-directory tmp-name1)) (ignore-errors (delete-file tmp-name1)) (ignore-errors (delete-file tmp-name2)))))) +(defvar tramp--test-start-time nil + "Keep the start time of the current test, a float number.") + (defsubst tramp--test-file-attributes-equal-p (attr1 attr2) "Check, whether file attributes ATTR1 and ATTR2 are equal. -They might differ only in access time." - (setcar (nthcdr 4 attr1) tramp-time-dont-know) - (setcar (nthcdr 4 attr2) tramp-time-dont-know) - (equal attr1 attr2)) +They might differ only in time attributes or directory size." + (let ((attr1 (copy-sequence attr1)) + (attr2 (copy-sequence attr2)) + (start-time (- tramp--test-start-time 10))) + ;; Link number. For directories, it includes the number of + ;; subdirectories. Set it to 1. + (when (eq (tramp-compat-file-attribute-type attr1) t) + (setcar (nthcdr 1 attr1) 1)) + (when (eq (tramp-compat-file-attribute-type attr2) t) + (setcar (nthcdr 1 attr2) 1)) + ;; Access time. + (setcar (nthcdr 4 attr1) tramp-time-dont-know) + (setcar (nthcdr 4 attr2) tramp-time-dont-know) + ;; Modification time. If any of the time values is "don't know", + ;; we cannot compare, and we normalize the time stamps. If the + ;; time value is newer than the test start time, normalize it, + ;; because due to caching the time stamps could differ slightly (a + ;; few seconds). We use a test start time minus 10 seconds, in + ;; order to compensate a possible timestamp resolution higher than + ;; a second on the remote machine. + (when (or (tramp-compat-time-equal-p + (tramp-compat-file-attribute-modification-time attr1) + tramp-time-dont-know) + (tramp-compat-time-equal-p + (tramp-compat-file-attribute-modification-time attr2) + tramp-time-dont-know)) + (setcar (nthcdr 5 attr1) tramp-time-dont-know) + (setcar (nthcdr 5 attr2) tramp-time-dont-know)) + (when (< start-time + (float-time (tramp-compat-file-attribute-modification-time attr1))) + (setcar (nthcdr 5 attr1) tramp-time-dont-know)) + (when (< start-time + (float-time (tramp-compat-file-attribute-modification-time attr2))) + (setcar (nthcdr 5 attr2) tramp-time-dont-know)) + ;; Status change time. Dito. + (when (or (tramp-compat-time-equal-p + (tramp-compat-file-attribute-status-change-time attr1) + tramp-time-dont-know) + (tramp-compat-time-equal-p + (tramp-compat-file-attribute-status-change-time attr2) + tramp-time-dont-know)) + (setcar (nthcdr 6 attr1) tramp-time-dont-know) + (setcar (nthcdr 6 attr2) tramp-time-dont-know)) + (when + (< start-time + (float-time + (tramp-compat-file-attribute-status-change-time attr1))) + (setcar (nthcdr 6 attr1) tramp-time-dont-know)) + (when + (< start-time + (float-time (tramp-compat-file-attribute-status-change-time attr2))) + (setcar (nthcdr 6 attr2) tramp-time-dont-know)) + ;; Size. Set it to 0 for directories, because it might have + ;; changed. For example the upper directory "../". + (when (eq (tramp-compat-file-attribute-type attr1) t) + (setcar (nthcdr 7 attr1) 0)) + (when (eq (tramp-compat-file-attribute-type attr2) t) + (setcar (nthcdr 7 attr2) 0)) + ;; The check. + (unless (equal attr1 attr2) (tramp--test-message "%S\n%S" attr1 attr2)) + (equal attr1 attr2))) ;; This isn't 100% correct, but better than no explainer at all. (put #'tramp--test-file-attributes-equal-p 'ert-explainer #'ert--explain-equal) @@ -3107,32 +3174,31 @@ They might differ only in access time." (progn (make-directory tmp-name1) (should (file-directory-p tmp-name1)) + (setq tramp--test-start-time + (float-time + (tramp-compat-file-attribute-modification-time + (file-attributes tmp-name1)))) (make-directory tmp-name2) (should (file-directory-p tmp-name2)) (write-region "foo" nil (expand-file-name "foo" tmp-name2)) (write-region "bar" nil (expand-file-name "bar" tmp-name2)) (write-region "boz" nil (expand-file-name "boz" tmp-name2)) + (setq attr (directory-files-and-attributes tmp-name2)) (should (consp attr)) - ;; Dumb remote shells without perl(1) or stat(1) are not - ;; able to return the date correctly. They say "don't know". (dolist (elt attr) - (unless - (tramp-compat-time-equal-p - (nth - 5 (file-attributes (expand-file-name (car elt) tmp-name2))) - tramp-time-dont-know) - (should - (tramp--test-file-attributes-equal-p - (file-attributes (expand-file-name (car elt) tmp-name2)) - (cdr elt))))) + (should + (tramp--test-file-attributes-equal-p + (file-attributes (expand-file-name (car elt) tmp-name2)) + (cdr elt)))) + (setq attr (directory-files-and-attributes tmp-name2 'full)) + (should (consp attr)) (dolist (elt attr) - (unless (tramp-compat-time-equal-p - (nth 5 (file-attributes (car elt))) tramp-time-dont-know) - (should - (tramp--test-file-attributes-equal-p - (file-attributes (car elt)) (cdr elt))))) + (should + (tramp--test-file-attributes-equal-p + (file-attributes (car elt)) (cdr elt)))) + (setq attr (directory-files-and-attributes tmp-name2 nil "^b")) (should (equal (mapcar #'car attr) '("bar" "boz")))) @@ -3143,7 +3209,13 @@ They might differ only in access time." "Check `file-modes'. This tests also `file-executable-p', `file-writable-p' and `set-file-modes'." (skip-unless (tramp--test-enabled)) - (skip-unless (or (tramp--test-sh-p) (tramp--test-sudoedit-p))) + (skip-unless + (or (tramp--test-sh-p) (tramp--test-sudoedit-p) + ;; Not all tramp-gvfs.el methods support changing the file mode. + (and + (tramp--test-gvfs-p) + (string-match-p + "ftp" (file-remote-p tramp-test-temporary-file-directory 'method))))) (dolist (quoted (if (tramp--test-expensive-test) '(nil t) '(nil))) (let ((tmp-name (tramp--test-make-temp-name nil quoted))) @@ -3159,7 +3231,8 @@ This tests also `file-executable-p', `file-writable-p' and `set-file-modes'." (should (= (file-modes tmp-name) #o444)) (should-not (file-executable-p tmp-name)) ;; A file is always writable for user "root". - (unless (zerop (nth 2 (file-attributes tmp-name))) + (unless (zerop (tramp-compat-file-attribute-user-id + (file-attributes tmp-name))) (should-not (file-writable-p tmp-name)))) ;; Cleanup. @@ -3443,7 +3516,8 @@ This tests also `make-symbolic-link', `file-truename' and `add-name-to-file'." "Check `set-file-times' and `file-newer-than-file-p'." (skip-unless (tramp--test-enabled)) (skip-unless - (or (tramp--test-adb-p) (tramp--test-sh-p) (tramp--test-sudoedit-p))) + (or (tramp--test-adb-p) (tramp--test-gvfs-p) + (tramp--test-sh-p) (tramp--test-sudoedit-p))) (dolist (quoted (if (tramp--test-expensive-test) '(nil t) '(nil))) (let ((tmp-name1 (tramp--test-make-temp-name nil quoted)) @@ -3453,16 +3527,22 @@ This tests also `make-symbolic-link', `file-truename' and `add-name-to-file'." (progn (write-region "foo" nil tmp-name1) (should (file-exists-p tmp-name1)) - (should (consp (nth 5 (file-attributes tmp-name1)))) + (should (consp (tramp-compat-file-attribute-modification-time + (file-attributes tmp-name1)))) ;; Skip the test, if the remote handler is not able to set ;; the correct time. (skip-unless (set-file-times tmp-name1 (seconds-to-time 1))) ;; Dumb remote shells without perl(1) or stat(1) are not ;; able to return the date correctly. They say "don't know". (unless (tramp-compat-time-equal-p - (nth 5 (file-attributes tmp-name1)) tramp-time-dont-know) + (tramp-compat-file-attribute-modification-time + (file-attributes tmp-name1)) + tramp-time-dont-know) (should - (equal (nth 5 (file-attributes tmp-name1)) (seconds-to-time 1))) + (tramp-compat-time-equal-p + (tramp-compat-file-attribute-modification-time + (file-attributes tmp-name1)) + (seconds-to-time 1))) (write-region "bla" nil tmp-name2) (should (file-exists-p tmp-name2)) (should (file-newer-than-file-p tmp-name2 tmp-name1)) @@ -4109,8 +4189,9 @@ This tests also `make-symbolic-link', `file-truename' and `add-name-to-file'." (with-timeout (10 (tramp--test-timeout-handler)) (while (accept-process-output proc 0 nil t))) ;; We cannot use `string-equal', because tramp-adb.el - ;; echoes also the sent string. - (should (string-match "killed\n\\'" (buffer-string)))) + ;; echoes also the sent string. And a remote macOS sends + ;; a slightly modified string. + (should (string-match "killed.*\n\\'" (buffer-string)))) ;; Cleanup. (ignore-errors (delete-process proc))) @@ -5108,7 +5189,7 @@ This requires restrictions of file name syntax." (string-equal (funcall (if quoted #'tramp-compat-file-name-quote #'identity) - (car (file-attributes file3))) + (tramp-compat-file-attribute-type (file-attributes file3))) (file-remote-p (file-truename file1) 'localname))) ;; Check file contents. (with-temp-buffer @@ -5195,7 +5276,10 @@ This requires restrictions of file name syntax." (should-not (file-exists-p file1)))) ;; Check, that environment variables are set correctly. - (when (and (tramp--test-expensive-test) (tramp--test-sh-p)) + ;; We do not run on macOS due to encoding problems. See + ;; Bug#36940. + (when (and (tramp--test-expensive-test) (tramp--test-sh-p) + (not (eq system-type 'darwin))) (dolist (elt files) (let ((envvar (concat "VAR_" (upcase (md5 elt)))) (elt (encode-coding-string elt coding-system-for-read)) diff --git a/texi/tramp.texi b/texi/tramp.texi index 3e8add2..1185e0e 100644 --- a/texi/tramp.texi +++ b/texi/tramp.texi @@ -125,7 +125,7 @@ Configuring @value{tramp} for use * Connection types:: Types of connections to remote hosts. * Inline methods:: Inline methods. * External methods:: External methods. -* GVFS based methods:: GVFS based external methods. +* GVFS-based methods:: @acronym{GVFS}-based external methods. * Default Method:: Selecting a default method. * Default User:: Selecting a default user. * Default Host:: Selecting a default host. @@ -545,9 +545,9 @@ of the local file name is the share exported by the remote host, @anchor{Quick Start Guide: GVFS-based methods} -@section Using GVFS-based methods +@section Using @acronym{GVFS}-based methods @cindex methods, gvfs -@cindex gvfs based methods +@cindex gvfs-based methods @cindex method @option{sftp} @cindex @option{sftp} method @cindex method @option{afp} @@ -557,10 +557,9 @@ of the local file name is the share exported by the remote host, @cindex @option{dav} method @cindex @option{davs} method -On systems, which have installed the virtual file system for the -@acronym{GNOME} Desktop (GVFS), its offered methods could be used by -@value{tramp}. Examples are -@file{@trampfn{sftp,user@@host,/path/to/file}}, +On systems, which have installed @acronym{GVFS, the GNOME Virtual File +System}, its offered methods could be used by @value{tramp}. Examples +are @file{@trampfn{sftp,user@@host,/path/to/file}}, @file{@trampfn{afp,user@@host,/path/to/file}} (accessing Apple's AFP file system), @file{@trampfn{dav,user@@host,/path/to/file}} and @file{@trampfn{davs,user@@host,/path/to/file}} (for WebDAV shares). @@ -576,10 +575,10 @@ file system), @file{@trampfn{dav,user@@host,/path/to/file}} and @cindex @option{nextcloud} method @cindex nextcloud -GVFS-based methods include also @acronym{GNOME} Online Accounts, which -support the @option{Files} service. These are the Google Drive file -system, and the OwnCloud/NextCloud file system. The file name syntax -is here always +@acronym{GVFS}-based methods include also @acronym{GNOME} Online +Accounts, which support the @option{Files} service. These are the +Google Drive file system, and the OwnCloud/NextCloud file system. The +file name syntax is here always @file{@trampfn{gdrive,john.doe@@gmail.com,/path/to/file}} (@samp{john.doe@@gmail.com} stands here for your Google Drive account), or @file{@trampfn{nextcloud,user@@host#8081,/path/to/file}} @@ -645,7 +644,7 @@ might be used in your init file: * Connection types:: Types of connections to remote hosts. * Inline methods:: Inline methods. * External methods:: External methods. -* GVFS based methods:: GVFS based external methods. +* GVFS-based methods:: @acronym{GVFS}-based external methods. * Default Method:: Selecting a default method. Here we also try to help those who don't have the foggiest which method @@ -1170,8 +1169,8 @@ information}. Supported properties are @samp{mount-args}, @samp{copyto-args} and @samp{moveto-args}. Access via @option{rclone} is slow. If you have an alternative method -for accessing the system storage, you shall prefer this. @ref{GVFS -based methods} for example, methods @option{gdrive} and +for accessing the system storage, you shall prefer this. +@ref{GVFS-based methods} for example, methods @option{gdrive} and @option{nextcloud}. @strong{Note}: The @option{rclone} method is experimental, don't use @@ -1180,20 +1179,20 @@ it in production systems! @end table -@node GVFS based methods -@section GVFS based external methods +@node GVFS-based methods +@section @acronym{GVFS}-based external methods @cindex methods, gvfs -@cindex gvfs based methods +@cindex gvfs-based methods @cindex dbus -GVFS is the virtual file system for the @acronym{GNOME} Desktop, -@uref{https://en.wikipedia.org/wiki/GVFS}. Remote files on GVFS are -mounted locally through FUSE and @value{tramp} uses this locally -mounted directory internally. +@acronym{GVFS} is the virtual file system for the @acronym{GNOME} +Desktop, @uref{https://en.wikipedia.org/wiki/GVFS}. Remote files on +@acronym{GVFS} are mounted locally through FUSE and @value{tramp} uses +this locally mounted directory internally. -Emacs uses the D-Bus mechanism to communicate with GVFS@. Emacs must -have the message bus system, D-Bus integration active, @pxref{Top, , -D-Bus, dbus}. +Emacs uses the D-Bus mechanism to communicate with @acronym{GVFS}@. +Emacs must have the message bus system, D-Bus integration active, +@pxref{Top, , D-Bus, dbus}. @table @asis @item @option{afp} @@ -1216,9 +1215,10 @@ syntax requires a leading volume (share) name, for example: based on standard protocols, such as HTTP@. @option{davs} does the same but with SSL encryption. Both methods support the port numbers. -Paths being part of the WebDAV volume to be mounted by GVFS, as it is -common for OwnCloud or NextCloud file names, are not supported by -these methods. See method @option{nextcloud} for handling them. +Paths being part of the WebDAV volume to be mounted by @acronym{GVFS}, +as it is common for OwnCloud or NextCloud file names, are not +supported by these methods. See method @option{nextcloud} for +handling them. @item @option{gdrive} @cindex method @option{gdrive} @@ -1259,13 +1259,26 @@ that for security reasons refuse @command{ssh} connections. @end table @defopt tramp-gvfs-methods -This user option is a list of external methods for GVFS@. By default, -this list includes @option{afp}, @option{dav}, @option{davs}, -@option{gdrive}, @option{nextcloud} and @option{sftp}. Other methods -to include are @option{ftp}, @option{http}, @option{https} and -@option{smb}. These methods are not intended to be used directly as -GVFS based method. Instead, they are added here for the benefit of -@ref{Archive file names}. +This user option is a list of external methods for @acronym{GVFS}@. +By default, this list includes @option{afp}, @option{dav}, +@option{davs}, @option{gdrive}, @option{nextcloud} and @option{sftp}. +Other methods to include are @option{ftp}, @option{http}, +@option{https} and @option{smb}. These methods are not intended to be +used directly as @acronym{GVFS}-based method. Instead, they are added +here for the benefit of @ref{Archive file names}. + +If you want to use @acronym{GVFS}-based @option{ftp} or @option{smb} +methods, you must add them to @code{tramp-gvfs-methods}, and you must +disable the corresponding Tramp package by setting +@code{tramp-ftp-method} or @code{tramp-smb-method} to @code{nil}, +respectively: + +@lisp +@group +(add-to-list 'tramp-gvfs-methods "ftp") +(customize-set-variable 'tramp-ftp-method nil) +@end group +@end lisp @end defopt @@ -2925,9 +2938,10 @@ host when the variable @code{default-directory} is remote: @end group @end lisp -Remote processes do not apply to GVFS (see @ref{GVFS based methods}) -because the remote file system is mounted on the local host and -@value{tramp} just accesses by changing the @code{default-directory}. +Remote processes do not apply to @acronym{GVFS} (see @ref{GVFS-based +methods}) because the remote file system is mounted on the local host +and @value{tramp} just accesses by changing the +@code{default-directory}. @value{tramp} starts a remote process when a command is executed in a remote file or directory buffer. As of now, these packages have been @@ -3311,10 +3325,10 @@ killing all buffers related to remote connections. @cindex archive method @value{tramp} offers also transparent access to files inside file -archives. This is possible only on machines which have installed the -virtual file system for the @acronym{GNOME} Desktop (GVFS), @ref{GVFS -based methods}. Internally, file archives are mounted via the GVFS -@option{archive} method. +archives. This is possible only on machines which have installed +@acronym{GVFS, the GNOME Virtual File System}, @ref{GVFS-based +methods}. Internally, file archives are mounted via the +@acronym{GVFS} @option{archive} method. A file archive is a regular file of kind @file{/path/to/dir/file.EXT}. The extension @samp{.EXT} identifies the type of the file archive. A @@ -3337,9 +3351,9 @@ file names as well. @vindex tramp-archive-suffixes File archives are identified by the file name extension @samp{.EXT}. -Since GVFS uses internally the library @code{libarchive(3)}, all -suffixes, which are accepted by this library, work also for archive -file names. Accepted suffixes are listed in the constant +Since @acronym{GVFS} uses internally the library @code{libarchive(3)}, +all suffixes, which are accepted by this library, work also for +archive file names. Accepted suffixes are listed in the constant @code{tramp-archive-suffixes}. They are @itemize @@ -3507,11 +3521,11 @@ row are possible, like @file{/path/to/dir/file.tar.gz.uu/dir/file}. @vindex tramp-archive-all-gvfs-methods An archive file name could be a remote file name, as in @file{/ftp:anonymous@@ftp.gnu.org:/gnu/tramp/tramp-2.3.2.tar.gz/INSTALL}. -Since all file operations are mapped internally to GVFS operations, -remote file names supported by @code{tramp-gvfs} perform better, -because no local copy of the file archive must be downloaded first. -For example, @samp{/sftp:user@@host:...} performs better than the -similar @samp{/scp:user@@host:...}. See the constant +Since all file operations are mapped internally to @acronym{GVFS} +operations, remote file names supported by @code{tramp-gvfs} perform +better, because no local copy of the file archive must be downloaded +first. For example, @samp{/sftp:user@@host:...} performs better than +the similar @samp{/scp:user@@host:...}. See the constant @code{tramp-archive-all-gvfs-methods} for a complete list of @code{tramp-gvfs} supported method names. diff --git a/texi/trampver.texi b/texi/trampver.texi index 0254776..6a2daea 100644 --- a/texi/trampver.texi +++ b/texi/trampver.texi @@ -8,7 +8,7 @@ @c In the Tramp GIT, the version numbers are auto-frobbed from @c tramp.el, and the bug report address is auto-frobbed from @c configure.ac. -@set trampver 2.4.2.1 +@set trampver 2.4.2.2 @set tramp-bug-report-address tramp-devel@@gnu.org @set emacsver 24.4 diff --git a/tramp-adb.el b/tramp-adb.el index fb84aa1..df4778c 100644 --- a/tramp-adb.el +++ b/tramp-adb.el @@ -232,96 +232,100 @@ pass to the OPERATION." ;; code could be shared? (defun tramp-adb-handle-file-truename (filename) "Like `file-truename' for Tramp files." - ;; Preserve trailing "/". + ;; Preserve trailing "/". (funcall - (if (string-equal (file-name-nondirectory filename) "") + (if (tramp-compat-directory-name-p filename) #'file-name-as-directory #'identity) - (with-parsed-tramp-file-name (expand-file-name filename) nil - (tramp-make-tramp-file-name - v - (with-tramp-file-property v localname "file-truename" - (let ((result nil) ; result steps in reverse order - (quoted (tramp-compat-file-name-quoted-p localname))) - (tramp-message v 4 "Finding true name for `%s'" filename) - (let* ((steps (split-string localname "/" 'omit)) - (localnamedir (tramp-run-real-handler - 'file-name-as-directory (list localname))) - (is-dir (string= localname localnamedir)) - (thisstep nil) - (numchase 0) - ;; Don't make the following value larger than - ;; necessary. People expect an error message in a - ;; timely fashion when something is wrong; otherwise - ;; they might think that Emacs is hung. Of course, - ;; correctness has to come first. - (numchase-limit 20) - symlink-target) - (while (and steps (< numchase numchase-limit)) - (setq thisstep (pop steps)) - (tramp-message - v 5 "Check %s" - (string-join - (append '("") (reverse result) (list thisstep)) "/")) - (setq symlink-target - (tramp-compat-file-attribute-type - (file-attributes - (tramp-make-tramp-file-name - v - (string-join - (append '("") (reverse result) (list thisstep)) "/"))))) - (cond ((string= "." thisstep) - (tramp-message v 5 "Ignoring step `.'")) - ((string= ".." thisstep) - (tramp-message v 5 "Processing step `..'") - (pop result)) - ((stringp symlink-target) - ;; It's a symlink, follow it. - (tramp-message v 5 "Follow symlink to %s" symlink-target) - (setq numchase (1+ numchase)) - (when (file-name-absolute-p symlink-target) - (setq result nil)) - ;; If the symlink was absolute, we'll get a string - ;; like "/user@host:/some/target"; extract the - ;; "/some/target" part from it. - (when (tramp-tramp-file-p symlink-target) - (unless (tramp-equal-remote filename symlink-target) - (tramp-error - v 'file-error - "Symlink target `%s' on wrong host" symlink-target)) - (setq symlink-target localname)) - (setq steps - (append (split-string symlink-target "/" 'omit) - steps))) - (t - ;; It's a file. - (setq result (cons thisstep result))))) - (when (>= numchase numchase-limit) - (tramp-error - v 'file-error - "Maximum number (%d) of symlinks exceeded" numchase-limit)) - (setq result (reverse result)) - ;; Combine list to form string. - (setq result - (if result - (string-join (cons "" result) "/") - "/")) - (when (and is-dir (or (string-empty-p result) - (not (string= (substring result -1) "/")))) - (setq result (concat result "/")))) - - ;; Detect cycle. - (when (and (file-symlink-p filename) - (string-equal result localname)) - (tramp-error - v 'file-error - "Apparent cycle of symbolic links for %s" filename)) - ;; If the resulting localname looks remote, we must quote it - ;; for security reasons. - (when (or quoted (file-remote-p result)) - (let (file-name-handler-alist) - (setq result (tramp-compat-file-name-quote result)))) - (tramp-message v 4 "True name of `%s' is `%s'" localname result) - result)))))) + ;; Quote properly. + (funcall + (if (tramp-compat-file-name-quoted-p filename) + #'tramp-compat-file-name-quote #'identity) + (with-parsed-tramp-file-name + (tramp-compat-file-name-unquote (expand-file-name filename)) nil + (tramp-make-tramp-file-name + v + (with-tramp-file-property v localname "file-truename" + (let (result) ; result steps in reverse order + (tramp-message v 4 "Finding true name for `%s'" filename) + (let* ((steps (split-string localname "/" 'omit)) + (localnamedir (tramp-run-real-handler + 'file-name-as-directory (list localname))) + (is-dir (string= localname localnamedir)) + (thisstep nil) + (numchase 0) + ;; Don't make the following value larger than + ;; necessary. People expect an error message in a + ;; timely fashion when something is wrong; otherwise + ;; they might think that Emacs is hung. Of course, + ;; correctness has to come first. + (numchase-limit 20) + symlink-target) + (while (and steps (< numchase numchase-limit)) + (setq thisstep (pop steps)) + (tramp-message + v 5 "Check %s" + (string-join + (append '("") (reverse result) (list thisstep)) "/")) + (setq symlink-target + (tramp-compat-file-attribute-type + (file-attributes + (tramp-make-tramp-file-name + v + (string-join + (append + '("") (reverse result) (list thisstep)) "/"))))) + (cond ((string= "." thisstep) + (tramp-message v 5 "Ignoring step `.'")) + ((string= ".." thisstep) + (tramp-message v 5 "Processing step `..'") + (pop result)) + ((stringp symlink-target) + ;; It's a symlink, follow it. + (tramp-message v 5 "Follow symlink to %s" symlink-target) + (setq numchase (1+ numchase)) + (when (file-name-absolute-p symlink-target) + (setq result nil)) + ;; If the symlink was absolute, we'll get a string + ;; like "/user@host:/some/target"; extract the + ;; "/some/target" part from it. + (when (tramp-tramp-file-p symlink-target) + (unless (tramp-equal-remote filename symlink-target) + (tramp-error + v 'file-error + "Symlink target `%s' on wrong host" symlink-target)) + (setq symlink-target localname)) + (setq steps + (append (split-string symlink-target "/" 'omit) + steps))) + (t + ;; It's a file. + (setq result (cons thisstep result))))) + (when (>= numchase numchase-limit) + (tramp-error + v 'file-error + "Maximum number (%d) of symlinks exceeded" numchase-limit)) + (setq result (reverse result)) + ;; Combine list to form string. + (setq result + (if result + (string-join (cons "" result) "/") + "/")) + (when (and is-dir (or (string-empty-p result) + (not (string= (substring result -1) "/")))) + (setq result (concat result "/")))) + + ;; Detect cycle. + (when (and (file-symlink-p filename) + (string-equal result localname)) + (tramp-error + v 'file-error + "Apparent cycle of symbolic links for %s" filename)) + ;; If the resulting localname looks remote, we must quote it + ;; for security reasons. + (when (file-remote-p result) + (setq result (tramp-compat-file-name-quote result 'top))) + (tramp-message v 4 "True name of `%s' is `%s'" localname result) + result))))))) (defun tramp-adb-handle-file-attributes (filename &optional id-format) "Like `file-attributes' for Tramp files." @@ -510,7 +514,6 @@ Emacs dired can't find files." (let ((par (expand-file-name ".." dir))) (unless (file-directory-p par) (make-directory par parents)))) - (tramp-flush-file-properties v (file-name-directory localname)) (tramp-flush-directory-properties v localname) (unless (or (tramp-adb-send-command-and-check v (format "mkdir %s" (tramp-shell-quote-argument localname))) @@ -521,10 +524,8 @@ Emacs dired can't find files." "Like `delete-directory' for Tramp files." (setq directory (expand-file-name directory)) (with-parsed-tramp-file-name (file-truename directory) nil - (tramp-flush-file-properties v (file-name-directory localname)) (tramp-flush-directory-properties v localname)) (with-parsed-tramp-file-name directory nil - (tramp-flush-file-properties v (file-name-directory localname)) (tramp-flush-directory-properties v localname) (tramp-adb-barf-unless-okay v (format "%s %s" @@ -536,7 +537,6 @@ Emacs dired can't find files." "Like `delete-file' for Tramp files." (setq filename (expand-file-name filename)) (with-parsed-tramp-file-name filename nil - (tramp-flush-file-properties v (file-name-directory localname)) (tramp-flush-file-properties v localname) (tramp-adb-barf-unless-okay v (format "rm %s" (tramp-shell-quote-argument localname)) @@ -627,7 +627,6 @@ But handle the case, if the \"test\" command is not available." ;; We must also flush the cache of the directory, because ;; `file-attributes' reads the values from there. - (tramp-flush-file-properties v (file-name-directory localname)) (tramp-flush-file-properties v localname) (let* ((curbuf (current-buffer)) (tmpfile (tramp-compat-make-temp-file filename))) @@ -665,14 +664,12 @@ But handle the case, if the \"test\" command is not available." (defun tramp-adb-handle-set-file-modes (filename mode) "Like `set-file-modes' for Tramp files." (with-parsed-tramp-file-name filename nil - (tramp-flush-file-properties v (file-name-directory localname)) (tramp-flush-file-properties v localname) (tramp-adb-send-command-and-check v (format "chmod %o %s" mode localname)))) (defun tramp-adb-handle-set-file-times (filename &optional time) "Like `set-file-times' for Tramp files." (with-parsed-tramp-file-name filename nil - (tramp-flush-file-properties v (file-name-directory localname)) (tramp-flush-file-properties v localname) (let ((time (if (or (null time) (tramp-compat-time-equal-p time tramp-time-doesnt-exist) @@ -711,7 +708,8 @@ PRESERVE-UID-GID and PRESERVE-EXTENDED-ATTRIBUTES are completely ignored." (with-parsed-tramp-file-name (if t1 filename 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))) + (when (and (file-directory-p newname) + (not (tramp-compat-directory-name-p newname))) (tramp-error v 'file-error "File is a directory %s" newname)) (with-tramp-progress-reporter @@ -722,7 +720,6 @@ PRESERVE-UID-GID and PRESERVE-EXTENDED-ATTRIBUTES are completely ignored." ;; We must also flush the cache of the directory, ;; because `file-attributes' reads the values from ;; there. - (tramp-flush-file-properties v (file-name-directory l2)) (tramp-flush-file-properties v l2) ;; Short track. (tramp-adb-barf-unless-okay @@ -757,8 +754,6 @@ PRESERVE-UID-GID and PRESERVE-EXTENDED-ATTRIBUTES are completely ignored." ;; We must also flush the cache of the directory, ;; because `file-attributes' reads the values from ;; there. - (tramp-flush-file-properties - v (file-name-directory localname)) (tramp-flush-file-properties v localname) (when (tramp-adb-execute-adb-command v "push" @@ -791,7 +786,8 @@ PRESERVE-UID-GID and PRESERVE-EXTENDED-ATTRIBUTES are completely ignored." (with-parsed-tramp-file-name (if t1 filename 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))) + (when (and (file-directory-p newname) + (not (tramp-compat-directory-name-p newname))) (tramp-error v 'file-error "File is a directory %s" newname)) (with-tramp-progress-reporter @@ -803,9 +799,7 @@ PRESERVE-UID-GID and PRESERVE-EXTENDED-ATTRIBUTES are completely ignored." (l2 (tramp-compat-file-local-name newname))) ;; We must also flush the cache of the directory, because ;; `file-attributes' reads the values from there. - (tramp-flush-file-properties v (file-name-directory l1)) (tramp-flush-file-properties v l1) - (tramp-flush-file-properties v (file-name-directory l2)) (tramp-flush-file-properties v l2) ;; Short track. (tramp-adb-barf-unless-okay diff --git a/tramp-cache.el b/tramp-cache.el index 489f81a..6e15469 100644 --- a/tramp-cache.el +++ b/tramp-cache.el @@ -193,6 +193,23 @@ Returns VALUE." (let ((var (intern (concat "tramp-cache-set-count-" property)))) (makunbound var)))) +(defun tramp-flush-file-upper-properties (key file) + "Remove some properties of FILE's upper directory." + (when (file-name-absolute-p file) + (let ((file (directory-file-name (file-name-directory file)))) + ;; Unify localname. Remove hop from `tramp-file-name' structure. + (setq file (tramp-compat-file-name-unquote file) + key (copy-tramp-file-name key)) + (setf (tramp-file-name-localname key) file + (tramp-file-name-hop key) nil) + (maphash + (lambda (property _value) + (when (string-match-p + "^\\(directory-\\|file-name-all-completions\\|file-entries\\)" + property) + (tramp-flush-file-property key file property))) + (tramp-get-hash-table key))))) + ;;;###tramp-autoload (defun tramp-flush-file-properties (key file) "Remove all properties of FILE in the cache context of KEY." @@ -209,7 +226,9 @@ Returns VALUE." ;; Remove file properties of symlinks. (when (and (stringp truename) (not (string-equal file (directory-file-name truename)))) - (tramp-flush-file-properties key truename)))) + (tramp-flush-file-properties key truename)) + ;; Remove selected properties of upper directory. + (tramp-flush-file-upper-properties key file))) ;;;###tramp-autoload (defun tramp-flush-directory-properties (key directory) @@ -231,7 +250,9 @@ Remove also properties of all files in subdirectories." ;; Remove file properties of symlinks. (when (and (stringp truename) (not (string-equal directory (directory-file-name truename)))) - (tramp-flush-directory-properties key truename)))) + (tramp-flush-directory-properties key truename)) + ;; Remove selected properties of upper directory. + (tramp-flush-file-upper-properties key directory))) ;; Reverting or killing a buffer should also flush file properties. ;; They could have been changed outside Tramp. In eshell, "ls" would diff --git a/tramp-compat.el b/tramp-compat.el index 6b855e6..2f50c0f 100644 --- a/tramp-compat.el +++ b/tramp-compat.el @@ -136,6 +136,14 @@ looked up, a numeric value, either an integer or a float, is returned." (nth 3 attributes)))) +(defalias 'tramp-compat-file-attribute-access-time + (if (fboundp 'file-attribute-access-time) + #'file-attribute-access-time + (lambda (attributes) + "The last access time in ATTRIBUTES returned by `file-attributes'. +This a Lisp timestamp in the style of `current-time'." + (nth 4 attributes)))) + (defalias 'tramp-compat-file-attribute-modification-time (if (fboundp 'file-attribute-modification-time) #'file-attribute-modification-time @@ -145,6 +153,16 @@ This is the time of the last change to the file's contents, and is a Lisp timestamp in the style of `current-time'." (nth 5 attributes)))) +(defalias 'tramp-compat-file-attribute-status-change-time + (if (fboundp 'file-attribute-status-change-time) + #'file-attribute-status-change-time + (lambda (attributes) + "The status modification time in ATTRIBUTES returned by `file-attributes'. +This is the time of last change to the file's attributes: owner +and group, access mode bits, etc., and is a Lisp timestamp in the +style of `current-time'." + (nth 6 attributes)))) + (defalias 'tramp-compat-file-attribute-size (if (fboundp 'file-attribute-size) #'file-attribute-size @@ -209,24 +227,31 @@ If NAME is a remote file name and TOP is nil, check the local part of NAME." (string-prefix-p "/:" (tramp-compat-file-local-name name)))))) (defalias 'tramp-compat-file-name-quote - (if (fboundp 'file-name-quote) + (if (and + (fboundp 'file-name-quote) + (equal (tramp-compat-funcall 'func-arity #'file-name-quote) '(1 . 2))) #'file-name-quote - (lambda (name) + (lambda (name &optional top) "Add the quotation prefix \"/:\" to file NAME. -If NAME is a remote file name, the local part of NAME is quoted." - (if (tramp-compat-file-name-quoted-p name) - name - (concat - (file-remote-p name) "/:" (tramp-compat-file-local-name name)))))) +If NAME is a remote file name and TOP is nil, the local part of NAME is quoted." + (let ((file-name-handler-alist (unless top file-name-handler-alist))) + (if (tramp-compat-file-name-quoted-p name top) + name + (concat + (file-remote-p name) "/:" (tramp-compat-file-local-name name))))))) (defalias 'tramp-compat-file-name-unquote - (if (fboundp 'file-name-unquote) + (if (and + (fboundp 'file-name-unquote) + (equal (tramp-compat-funcall 'func-arity #'file-name-unquote) '(1 . 2))) #'file-name-unquote - (lambda (name) + (lambda (name &optional top) "Remove quotation prefix \"/:\" from file NAME. -If NAME is a remote file name, the local part of NAME is unquoted." - (let ((localname (tramp-compat-file-local-name name))) - (when (tramp-compat-file-name-quoted-p localname) +If NAME is a remote file name and TOP is nil, the local part of +NAME is unquoted." + (let* ((file-name-handler-alist (unless top file-name-handler-alist)) + (localname (tramp-compat-file-local-name name))) + (when (tramp-compat-file-name-quoted-p localname top) (setq localname (if (= (length localname) 2) "/" (substring localname 2)))) (concat (file-remote-p name) localname))))) diff --git a/tramp-gvfs.el b/tramp-gvfs.el index 9d45e6a..b9b6b4b 100644 --- a/tramp-gvfs.el +++ b/tramp-gvfs.el @@ -471,6 +471,7 @@ It has been changed in GVFS 1.14.") ("gvfs-mount" . "mount") ("gvfs-move" . "move") ("gvfs-rm" . "remove") + ("gvfs-set-attribute" . "set") ("gvfs-trash" . "trash")) "List of cons cells, mapping \"gvfs-<command>\" to \"gio <command>\".") @@ -590,15 +591,15 @@ It has been changed in GVFS 1.14.") (process-file . ignore) (rename-file . tramp-gvfs-handle-rename-file) (set-file-acl . ignore) - (set-file-modes . ignore) + (set-file-modes . tramp-gvfs-handle-set-file-modes) (set-file-selinux-context . ignore) - (set-file-times . ignore) + (set-file-times . tramp-gvfs-handle-set-file-times) (set-visited-file-modtime . tramp-handle-set-visited-file-modtime) (shell-command . ignore) (start-file-process . ignore) (substitute-in-file-name . tramp-handle-substitute-in-file-name) (temporary-file-directory . tramp-handle-temporary-file-directory) - (tramp-set-file-uid-gid . ignore) + (tramp-set-file-uid-gid . tramp-gvfs-handle-set-file-uid-gid) (unhandled-file-name-directory . ignore) (vc-registered . ignore) (verify-visited-file-modtime . tramp-handle-verify-visited-file-modtime) @@ -765,7 +766,8 @@ file names." (with-parsed-tramp-file-name (if t1 filename 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))) + (when (and (file-directory-p newname) + (not (tramp-compat-directory-name-p newname))) (tramp-error v 'file-error "File is a directory %s" newname)) (if (or (and equal-remote @@ -816,12 +818,10 @@ file names." (when (and t1 (eq op 'rename)) (with-parsed-tramp-file-name filename nil - (tramp-flush-file-properties v (file-name-directory localname)) (tramp-flush-file-properties v localname))) (when t2 (with-parsed-tramp-file-name newname nil - (tramp-flush-file-properties v (file-name-directory localname)) (tramp-flush-file-properties v localname)))))))) (defun tramp-gvfs-handle-copy-file @@ -856,7 +856,6 @@ file names." (tramp-error v 'file-error "Couldn't delete non-empty %s" directory))) - (tramp-flush-file-properties v (file-name-directory localname)) (tramp-flush-directory-properties v localname) (unless (tramp-gvfs-send-command @@ -871,7 +870,6 @@ file names." (defun tramp-gvfs-handle-delete-file (filename &optional trash) "Like `delete-file' for Tramp files." (with-parsed-tramp-file-name filename nil - (tramp-flush-file-properties v (file-name-directory localname)) (tramp-flush-file-properties v localname) (unless (tramp-gvfs-send-command @@ -1263,6 +1261,12 @@ file-notify events." (with-tramp-file-property v localname "file-readable-p" (and (file-exists-p filename) (or (tramp-check-cached-permissions v ?r) + ;; `tramp-check-cached-permissions' doesn't handle + ;; symbolic links. + (and (stringp (file-symlink-p filename)) + (file-readable-p + (concat + (file-remote-p filename) (file-symlink-p filename)))) ;; If the user is different from what we guess to be ;; the user, we don't know. Let's check, whether ;; access is restricted explicitly. @@ -1295,7 +1299,6 @@ file-notify events." "Like `make-directory' for Tramp files." (setq dir (directory-file-name (expand-file-name dir))) (with-parsed-tramp-file-name dir nil - (tramp-flush-file-properties v (file-name-directory localname)) (tramp-flush-directory-properties v localname) (save-match-data (let ((ldir (file-name-directory dir))) @@ -1325,6 +1328,45 @@ file-notify events." (tramp-run-real-handler #'rename-file (list filename newname ok-if-already-exists)))) +(defun tramp-gvfs-handle-set-file-modes (filename mode) + "Like `set-file-modes' for Tramp files." + (with-parsed-tramp-file-name filename nil + (tramp-flush-file-properties v localname) + (tramp-gvfs-send-command + v "gvfs-set-attribute" "-t" "uint32" + (tramp-gvfs-url-file-name (tramp-make-tramp-file-name v)) + "unix::mode" (number-to-string mode)))) + +(defun tramp-gvfs-handle-set-file-times (filename &optional time) + "Like `set-file-times' for Tramp files." + (with-parsed-tramp-file-name filename nil + (tramp-flush-file-properties v localname) + (let ((time + (if (or (null time) + (tramp-compat-time-equal-p time tramp-time-doesnt-exist) + (tramp-compat-time-equal-p time tramp-time-dont-know)) + (current-time) + time))) + (tramp-gvfs-send-command + v "gvfs-set-attribute" "-t" "uint64" + (tramp-gvfs-url-file-name (tramp-make-tramp-file-name v)) + "time::modified" (format-time-string "%s" time))))) + +(defun tramp-gvfs-set-file-uid-gid (filename &optional uid gid) + "Like `tramp-set-file-uid-gid' for Tramp files." + (with-parsed-tramp-file-name filename nil + (tramp-flush-file-properties v localname) + (when (natnump uid) + (tramp-gvfs-send-command + v "gvfs-set-attribute" "-t" "uint32" + (tramp-gvfs-url-file-name (tramp-make-tramp-file-name v)) + "unix::uid" (number-to-string uid))) + (when (natnump gid) + (tramp-gvfs-send-command + v "gvfs-set-attribute" "-t" "uint32" + (tramp-gvfs-url-file-name (tramp-make-tramp-file-name v)) + "unix::gid" (number-to-string gid))))) + ;; File name conversions. diff --git a/tramp-loaddefs.el b/tramp-loaddefs.el index 4e4374b..8fde671 100644 --- a/tramp-loaddefs.el +++ b/tramp-loaddefs.el @@ -274,7 +274,7 @@ Zeroconf domain to be used for discovering services, like host names.") (defconst tramp-goa-service "org.gnome.OnlineAccounts" "\ The well known name of the GNOME Online Accounts service.") -(defconst tramp-gvfs-file-name-handler-alist '((access-file . tramp-handle-access-file) (add-name-to-file . tramp-handle-add-name-to-file) (copy-file . tramp-gvfs-handle-copy-file) (delete-directory . tramp-gvfs-handle-delete-directory) (delete-file . tramp-gvfs-handle-delete-file) (directory-file-name . tramp-handle-directory-file-name) (directory-files . tramp-handle-directory-files) (directory-files-and-attributes . tramp-handle-directory-files-and-attributes) (dired-compress-file . i [...] +(defconst tramp-gvfs-file-name-handler-alist '((access-file . tramp-handle-access-file) (add-name-to-file . tramp-handle-add-name-to-file) (copy-file . tramp-gvfs-handle-copy-file) (delete-directory . tramp-gvfs-handle-delete-directory) (delete-file . tramp-gvfs-handle-delete-file) (directory-file-name . tramp-handle-directory-file-name) (directory-files . tramp-handle-directory-files) (directory-files-and-attributes . tramp-handle-directory-files-and-attributes) (dired-compress-file . i [...] Alist of handler functions for Tramp GVFS method. Operations not mentioned here will be handled by the default Emacs primitives.") @@ -577,7 +577,7 @@ UU-encode the region between BEG and END. ;;;### (autoloads nil "trampver" "trampver.el" (0 0 0 0)) ;;; Generated autoloads from trampver.el -(defconst tramp-version "2.4.2.1" "\ +(defconst tramp-version "2.4.2.2" "\ This version of Tramp.") (defconst tramp-bug-report-address "tramp-de...@gnu.org" "\ diff --git a/tramp-rclone.el b/tramp-rclone.el index 9b3eab3..866e779 100644 --- a/tramp-rclone.el +++ b/tramp-rclone.el @@ -215,7 +215,8 @@ file names." (with-parsed-tramp-file-name (if t1 filename 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))) + (when (and (file-directory-p newname) + (not (tramp-compat-directory-name-p newname))) (tramp-error v 'file-error "File is a directory %s" newname)) (if (or (and t1 (not (tramp-rclone-file-name-p filename))) @@ -244,30 +245,22 @@ file names." (when (and t1 (eq op 'rename)) (with-parsed-tramp-file-name filename v1 - (tramp-flush-file-properties - v1 (file-name-directory v1-localname)) (tramp-flush-file-properties v1 v1-localname) (when (tramp-rclone-file-name-p filename) (tramp-rclone-flush-directory-cache v1) ;; The mount point's directory cache might need time ;; to flush. (while (file-exists-p filename) - (tramp-flush-file-properties - v1 (file-name-directory v1-localname)) (tramp-flush-file-properties v1 v1-localname))))) (when t2 (with-parsed-tramp-file-name newname v2 - (tramp-flush-file-properties - v2 (file-name-directory v2-localname)) (tramp-flush-file-properties v2 v2-localname) (when (tramp-rclone-file-name-p newname) (tramp-rclone-flush-directory-cache v2) ;; The mount point's directory cache might need time ;; to flush. (while (not (file-exists-p newname)) - (tramp-flush-file-properties - v2 (file-name-directory v2-localname)) (tramp-flush-file-properties v2 v2-localname)))))))))) (defun tramp-rclone-handle-copy-file @@ -292,7 +285,6 @@ file names." "Like `delete-directory' for Tramp files." (with-parsed-tramp-file-name (expand-file-name directory) nil (delete-directory (tramp-rclone-local-file-name directory) recursive trash) - (tramp-flush-file-properties v (file-name-directory localname)) (tramp-flush-directory-properties v localname) (tramp-rclone-flush-directory-cache v))) @@ -300,7 +292,6 @@ file names." "Like `delete-file' for Tramp files." (with-parsed-tramp-file-name (expand-file-name filename) nil (delete-file (tramp-rclone-local-file-name filename) trash) - (tramp-flush-file-properties v (file-name-directory localname)) (tramp-flush-file-properties v localname) (tramp-rclone-flush-directory-cache v))) diff --git a/tramp-sh.el b/tramp-sh.el index 6a82fef..217e73a 100644 --- a/tramp-sh.el +++ b/tramp-sh.el @@ -719,7 +719,7 @@ for($i = 0; $i < $n; $i++) $gid = ($ARGV[1] eq \"integer\") ? $stat[5] : \"\\\"\" . getgrgid($stat[5]) . \"\\\"\"; $filename =~ s/\"/\\\\\"/g; printf( - \"(\\\"%%s\\\" %%s %%u %%s %%s (%%u %%u) (%%u %%u) (%%u %%u) %%u.0 %%u t (%%u . %%u) (%%u . %%u))\\n\", + \"(\\\"%%s\\\" %%s %%u %%s %%s (%%u %%u) (%%u %%u) (%%u %%u) %%u %%u t %%u -1)\\n\", $filename, $type, $stat[3], @@ -733,10 +733,7 @@ for($i = 0; $i < $n; $i++) $stat[10] & 0xffff, $stat[7], $stat[2], - $stat[1] >> 16 & 0xffff, - $stat[1] & 0xffff, - $stat[0] >> 16 & 0xffff, - $stat[0] & 0xffff); + $stat[1]); } printf(\")\\n\");' \"$1\" \"$2\" 2>/dev/null" "Perl script implementing `directory-files-attributes' as Lisp `read'able @@ -1044,8 +1041,7 @@ component is used as the target of the symlink." ;; If TARGET is still remote, quote it. (if (tramp-tramp-file-p target) - (make-symbolic-link - (let (file-name-handler-alist) (tramp-compat-file-name-quote target)) + (make-symbolic-link (tramp-compat-file-name-quote target 'top) linkname ok-if-already-exists) (let ((ln (tramp-get-remote-ln v)) @@ -1069,7 +1065,6 @@ component is used as the target of the symlink." (tramp-error v 'file-already-exists localname) (delete-file linkname))) - (tramp-flush-file-properties v (file-name-directory localname)) (tramp-flush-file-properties v localname) ;; Right, they are on the same host, regardless of user, @@ -1091,108 +1086,113 @@ component is used as the target of the symlink." (defun tramp-sh-handle-file-truename (filename) "Like `file-truename' for Tramp files." - ;; Preserve trailing "/". + ;; Preserve trailing "/". (funcall - (if (string-equal (file-name-nondirectory filename) "") + (if (tramp-compat-directory-name-p filename) #'file-name-as-directory #'identity) - (with-parsed-tramp-file-name (expand-file-name filename) nil - (tramp-make-tramp-file-name - v - (with-tramp-file-property v localname "file-truename" - (let ((result nil) ; result steps in reverse order - (quoted (tramp-compat-file-name-quoted-p localname)) - (localname (tramp-compat-file-name-unquote localname))) - (tramp-message v 4 "Finding true name for `%s'" filename) - (cond - ;; Use GNU readlink --canonicalize-missing where available. - ((tramp-get-remote-readlink v) - (tramp-send-command-and-check - v - (format "%s --canonicalize-missing %s" - (tramp-get-remote-readlink v) - (tramp-shell-quote-argument localname))) - (with-current-buffer (tramp-get-connection-buffer v) - (goto-char (point-min)) - (setq result (buffer-substring (point-min) (point-at-eol))))) - - ;; Use Perl implementation. - ((and (tramp-get-remote-perl v) - (tramp-get-connection-property v "perl-file-spec" nil) - (tramp-get-connection-property v "perl-cwd-realpath" nil)) - (tramp-maybe-send-script - v tramp-perl-file-truename "tramp_perl_file_truename") - (setq result - (tramp-send-command-and-read - v - (format "tramp_perl_file_truename %s" - (tramp-shell-quote-argument localname))))) - - ;; Do it yourself. - (t (let ((steps (split-string localname "/" 'omit)) - (thisstep nil) - (numchase 0) - ;; Don't make the following value larger than - ;; necessary. People expect an error message in a - ;; timely fashion when something is wrong; - ;; otherwise they might think that Emacs is hung. - ;; Of course, correctness has to come first. - (numchase-limit 20) - symlink-target) - (while (and steps (< numchase numchase-limit)) - (setq thisstep (pop steps)) - (tramp-message - v 5 "Check %s" - (string-join - (append '("") (reverse result) (list thisstep)) "/")) - (setq symlink-target - (tramp-compat-file-attribute-type - (file-attributes - (tramp-make-tramp-file-name - v - (string-join - (append '("") (reverse result) (list thisstep)) "/") - 'nohop)))) - (cond ((string= "." thisstep) - (tramp-message v 5 "Ignoring step `.'")) - ((string= ".." thisstep) - (tramp-message v 5 "Processing step `..'") - (pop result)) - ((stringp symlink-target) - ;; It's a symlink, follow it. - (tramp-message - v 5 "Follow symlink to %s" symlink-target) - (setq numchase (1+ numchase)) - (when (file-name-absolute-p symlink-target) - (setq result nil)) - (setq steps - (append - (split-string symlink-target "/" 'omit) steps))) - (t - ;; It's a file. - (setq result (cons thisstep result))))) - (when (>= numchase numchase-limit) - (tramp-error - v 'file-error - "Maximum number (%d) of symlinks exceeded" numchase-limit)) - (setq result (reverse result)) - ;; Combine list to form string. - (setq result (if result (string-join (cons "" result) "/") "/")) - (when (string-empty-p result) (setq result "/"))))) - - ;; Detect cycle. - (when (and (file-symlink-p filename) - (string-equal result localname)) - (tramp-error - v 'file-error - "Apparent cycle of symbolic links for %s" filename)) - ;; If the resulting localname looks remote, we must quote it - ;; for security reasons. - (when (or quoted (file-remote-p result)) - (let (file-name-handler-alist) - (setq result (tramp-compat-file-name-quote result)))) - (tramp-message v 4 "True name of `%s' is `%s'" localname result) - result)) - 'nohop)))) + ;; Quote properly. + (funcall + (if (tramp-compat-file-name-quoted-p filename) + #'tramp-compat-file-name-quote #'identity) + (with-parsed-tramp-file-name + (tramp-compat-file-name-unquote (expand-file-name filename)) nil + (tramp-make-tramp-file-name + v + (with-tramp-file-property v localname "file-truename" + (let (result) ; result steps in reverse order + (tramp-message v 4 "Finding true name for `%s'" filename) + (cond + ;; Use GNU readlink --canonicalize-missing where available. + ((tramp-get-remote-readlink v) + (tramp-send-command-and-check + v + (format "%s --canonicalize-missing %s" + (tramp-get-remote-readlink v) + (tramp-shell-quote-argument localname))) + (with-current-buffer (tramp-get-connection-buffer v) + (goto-char (point-min)) + (setq result (buffer-substring (point-min) (point-at-eol))))) + + ;; Use Perl implementation. + ((and (tramp-get-remote-perl v) + (tramp-get-connection-property v "perl-file-spec" nil) + (tramp-get-connection-property v "perl-cwd-realpath" nil)) + (tramp-maybe-send-script + v tramp-perl-file-truename "tramp_perl_file_truename") + (setq result + (tramp-send-command-and-read + v + (format "tramp_perl_file_truename %s" + (tramp-shell-quote-argument localname))))) + + ;; Do it yourself. + (t (let ((steps (split-string localname "/" 'omit)) + (thisstep nil) + (numchase 0) + ;; Don't make the following value larger than + ;; necessary. People expect an error message in a + ;; timely fashion when something is wrong; + ;; otherwise they might think that Emacs is hung. + ;; Of course, correctness has to come first. + (numchase-limit 20) + symlink-target) + (while (and steps (< numchase numchase-limit)) + (setq thisstep (pop steps)) + (tramp-message + v 5 "Check %s" + (string-join + (append '("") (reverse result) (list thisstep)) "/")) + (setq symlink-target + (tramp-compat-file-attribute-type + (file-attributes + (tramp-make-tramp-file-name + v + (string-join + (append + '("") (reverse result) (list thisstep)) "/") + 'nohop)))) + (cond ((string= "." thisstep) + (tramp-message v 5 "Ignoring step `.'")) + ((string= ".." thisstep) + (tramp-message v 5 "Processing step `..'") + (pop result)) + ((stringp symlink-target) + ;; It's a symlink, follow it. + (tramp-message + v 5 "Follow symlink to %s" symlink-target) + (setq numchase (1+ numchase)) + (when (file-name-absolute-p symlink-target) + (setq result nil)) + (setq steps + (append + (split-string symlink-target "/" 'omit) + steps))) + (t + ;; It's a file. + (setq result (cons thisstep result))))) + (when (>= numchase numchase-limit) + (tramp-error + v 'file-error + "Maximum number (%d) of symlinks exceeded" numchase-limit)) + (setq result (reverse result)) + ;; Combine list to form string. + (setq result + (if result (string-join (cons "" result) "/") "/")) + (when (string-empty-p result) (setq result "/"))))) + + ;; Detect cycle. + (when (and (file-symlink-p filename) + (string-equal result localname)) + (tramp-error + v 'file-error + "Apparent cycle of symbolic links for %s" filename)) + ;; If the resulting localname looks remote, we must quote it + ;; for security reasons. + (when (file-remote-p result) + (setq result (tramp-compat-file-name-quote result 'top))) + (tramp-message v 4 "True name of `%s' is `%s'" localname result) + result)) + 'nohop))))) ;; Basic functions. @@ -1450,7 +1450,6 @@ of." (defun tramp-sh-handle-set-file-modes (filename mode) "Like `set-file-modes' for Tramp files." (with-parsed-tramp-file-name filename nil - (tramp-flush-file-properties v (file-name-directory localname)) (tramp-flush-file-properties v localname) ;; FIXME: extract the proper text from chmod's stderr. (tramp-barf-unless-okay @@ -1462,7 +1461,6 @@ of." "Like `set-file-times' for Tramp files." (with-parsed-tramp-file-name filename nil (when (tramp-get-remote-touch v) - (tramp-flush-file-properties v (file-name-directory localname)) (tramp-flush-file-properties v localname) (let ((time (if (or (null time) @@ -1875,7 +1873,6 @@ tramp-sh-handle-file-name-all-completions: internal error accessing `%s': `%s'" v2-localname))))) (tramp-error v2 'file-already-exists newname) (delete-file newname))) - (tramp-flush-file-properties v2 (file-name-directory v2-localname)) (tramp-flush-file-properties v2 v2-localname) (tramp-barf-unless-okay v1 @@ -1942,7 +1939,6 @@ tramp-sh-handle-file-name-all-completions: internal error accessing `%s': `%s'" ;; When newname did exist, we have wrong cached values. (when t2 (with-parsed-tramp-file-name newname nil - (tramp-flush-file-properties v (file-name-directory localname)) (tramp-flush-file-properties v localname)))))) (defun tramp-sh-handle-rename-file @@ -1998,7 +1994,8 @@ file names." (with-parsed-tramp-file-name (if t1 filename 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))) + (when (and (file-directory-p newname) + (not (tramp-compat-directory-name-p newname))) (tramp-error v 'file-error "File is a directory %s" newname)) (with-tramp-progress-reporter @@ -2072,15 +2069,11 @@ file names." ;; 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 (file-name-directory v1-localname)) (tramp-flush-file-properties v1 v1-localname))) ;; When newname did exist, we have wrong cached values. (when t2 (with-parsed-tramp-file-name newname v2 - (tramp-flush-file-properties - v2 (file-name-directory v2-localname)) (tramp-flush-file-properties v2 v2-localname)))))))) (defun tramp-do-copy-or-rename-file-via-buffer (op filename newname keep-date) @@ -2505,7 +2498,6 @@ The method used must be an out-of-band method." "Like `delete-directory' for Tramp files." (setq directory (expand-file-name directory)) (with-parsed-tramp-file-name directory nil - (tramp-flush-file-properties v (file-name-directory localname)) (tramp-flush-directory-properties v localname) (tramp-barf-unless-okay v (format "cd / && %s %s" @@ -2518,7 +2510,6 @@ The method used must be an out-of-band method." "Like `delete-file' for Tramp files." (setq filename (expand-file-name filename)) (with-parsed-tramp-file-name filename nil - (tramp-flush-file-properties v (file-name-directory localname)) (tramp-flush-file-properties v localname) (tramp-barf-unless-okay v (format "%s %s" @@ -2686,7 +2677,7 @@ The method used must be an out-of-band method." (when (file-symlink-p filename) (goto-char (search-backward "->" beg 'noerror))) (search-backward - (if (zerop (length (file-name-nondirectory filename))) + (if (tramp-compat-directory-name-p filename) "." (file-name-nondirectory filename)) beg 'noerror) @@ -3394,7 +3385,6 @@ the result will be a local, non-Tramp, file name." (when coding-system-used (set 'last-coding-system-used coding-system-used)))) - (tramp-flush-file-properties v (file-name-directory localname)) (tramp-flush-file-properties v localname) ;; We must protect `last-coding-system-used', now we have set it @@ -3785,7 +3775,8 @@ file-notify events." (intern-soft (replace-regexp-in-string "_" "-" (downcase x)))) (split-string (match-string 1 line) "," 'omit)) - (match-string 3 line)))) + (or (match-string 3 line) + (file-name-nondirectory (process-get proc 'watch-name)))))) ;; Usually, we would add an Emacs event now. Unfortunately, ;; `unread-command-events' does not accept several events at ;; once. Therefore, we apply the handler directly. diff --git a/tramp-smb.el b/tramp-smb.el index 9b87ed4..5df26a1 100644 --- a/tramp-smb.el +++ b/tramp-smb.el @@ -371,7 +371,6 @@ pass to the OPERATION." (delete-file newname))) ;; We must also flush the cache of the directory, because ;; `file-attributes' reads the values from there. - (tramp-flush-file-properties v2 (file-name-directory v2-localname)) (tramp-flush-file-properties v2 v2-localname) (unless (tramp-smb-send-command @@ -548,7 +547,6 @@ pass to the OPERATION." ;; When newname did exist, we have wrong cached values. (when t2 (with-parsed-tramp-file-name newname nil - (tramp-flush-file-properties v (file-name-directory localname)) (tramp-flush-file-properties v localname)))) ;; We must do it file-wise. @@ -591,12 +589,11 @@ PRESERVE-UID-GID and PRESERVE-EXTENDED-ATTRIBUTES are completely ignored." (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))) + (not (tramp-compat-directory-name-p newname))) (tramp-error v 'file-error "File is a directory %s" newname)) ;; We must also flush the cache of the directory, because ;; `file-attributes' reads the values from there. - (tramp-flush-file-properties v (file-name-directory localname)) (tramp-flush-file-properties v localname) (unless (tramp-smb-get-share v) (tramp-error @@ -631,7 +628,6 @@ PRESERVE-UID-GID and PRESERVE-EXTENDED-ATTRIBUTES are completely ignored." (with-parsed-tramp-file-name directory nil ;; We must also flush the cache of the directory, because ;; `file-attributes' reads the values from there. - (tramp-flush-file-properties v (file-name-directory localname)) (tramp-flush-directory-properties v localname) (unless (tramp-smb-send-command v (format @@ -657,7 +653,6 @@ PRESERVE-UID-GID and PRESERVE-EXTENDED-ATTRIBUTES are completely ignored." (with-parsed-tramp-file-name filename nil ;; We must also flush the cache of the directory, because ;; `file-attributes' reads the values from there. - (tramp-flush-file-properties v (file-name-directory localname)) (tramp-flush-file-properties v localname) (unless (tramp-smb-send-command v (format @@ -991,7 +986,7 @@ PRESERVE-UID-GID and PRESERVE-EXTENDED-ATTRIBUTES are completely ignored." (setq filename (expand-file-name filename)) (unless switches (setq switches "")) ;; Mark trailing "/". - (when (and (zerop (length (file-name-nondirectory filename))) + (when (and (tramp-compat-directory-name-p filename) (not full-directory-p)) (setq switches (concat switches "F"))) (if full-directory-p @@ -1154,7 +1149,6 @@ PRESERVE-UID-GID and PRESERVE-EXTENDED-ATTRIBUTES are completely ignored." (format "mkdir \"%s\"" file))) ;; We must also flush the cache of the directory, because ;; `file-attributes' reads the values from there. - (tramp-flush-file-properties v (file-name-directory localname)) (tramp-flush-file-properties v localname)) (unless (file-directory-p directory) (tramp-error v 'file-error "Couldn't make directory %s" directory))))) @@ -1181,8 +1175,7 @@ component is used as the target of the symlink." ;; If TARGET is still remote, quote it. (if (tramp-tramp-file-p target) - (make-symbolic-link - (let (file-name-handler-alist) (tramp-compat-file-name-quote target)) + (make-symbolic-link (tramp-compat-file-name-quote target 'top) linkname ok-if-already-exists) ;; Do the 'confirm if exists' thing. @@ -1202,7 +1195,6 @@ component is used as the target of the symlink." ;; We must also flush the cache of the directory, because ;; `file-attributes' reads the values from there. - (tramp-flush-file-properties v (file-name-directory localname)) (tramp-flush-file-properties v localname) (unless @@ -1341,7 +1333,8 @@ component is used as the target of the symlink." (if (tramp-tramp-file-p filename) filename 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))) + (when (and (file-directory-p newname) + (not (tramp-compat-directory-name-p newname))) (tramp-error v 'file-error "File is a directory %s" newname)) (with-tramp-progress-reporter @@ -1358,11 +1351,7 @@ component is used as the target of the symlink." ;; We must also flush the cache of the directory, because ;; `file-attributes' reads the values from there. - (tramp-flush-file-properties - v1 (file-name-directory v1-localname)) (tramp-flush-file-properties v1 v1-localname) - (tramp-flush-file-properties - v2 (file-name-directory v2-localname)) (tramp-flush-file-properties v2 v2-localname) (unless (tramp-smb-get-share v2) (tramp-error @@ -1548,7 +1537,6 @@ errors for shares like \"C$/\", which are common in Microsoft Windows." ;; We must also flush the cache of the directory, because ;; `file-attributes' reads the values from there. - (tramp-flush-file-properties v (file-name-directory localname)) (tramp-flush-file-properties v localname) (let ((curbuf (current-buffer)) (tmpfile (tramp-compat-make-temp-file filename))) @@ -1814,7 +1802,12 @@ Result is the list (LOCALNAME MODE SIZE MTIME)." (if (and sec min hour day month year) (encode-time sec min hour day - (cdr (assoc (downcase month) parse-time-months)) + ;; `parse-time-months' could be customized by the + ;; user, so we take its default value. + (cdr + (assoc + (downcase month) + (default-toplevel-value 'parse-time-months))) year) tramp-time-dont-know)) (list localname mode size mtime)))) diff --git a/tramp-sudoedit.el b/tramp-sudoedit.el index 0ded85f..80ce8f7 100644 --- a/tramp-sudoedit.el +++ b/tramp-sudoedit.el @@ -189,7 +189,6 @@ pass to the OPERATION." v2-localname))))) (tramp-error v2 'file-already-exists newname) (delete-file newname))) - (tramp-flush-file-properties v2 (file-name-directory v2-localname)) (tramp-flush-file-properties v2 v2-localname) (unless (tramp-sudoedit-send-command @@ -244,7 +243,8 @@ absolute file names." (with-parsed-tramp-file-name (if t1 filename 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))) + (when (and (file-directory-p newname) + (not (tramp-compat-directory-name-p newname))) (tramp-error v 'file-error "File is a directory %s" newname)) (if (or (and (file-remote-p filename) (not t1)) @@ -291,14 +291,10 @@ absolute file names." (when (and t1 (eq op 'rename)) (with-parsed-tramp-file-name filename v1 - (tramp-flush-file-properties - v1 (file-name-directory v1-localname)) (tramp-flush-file-properties v1 v1-localname))) (when t2 (with-parsed-tramp-file-name newname v2 - (tramp-flush-file-properties - v2 (file-name-directory v2-localname)) (tramp-flush-file-properties v2 v2-localname))))))) (defun tramp-sudoedit-handle-copy-file @@ -323,7 +319,6 @@ absolute file names." "Like `delete-directory' for Tramp files." (setq directory (expand-file-name directory)) (with-parsed-tramp-file-name directory nil - (tramp-flush-file-properties v (file-name-directory localname)) (tramp-flush-directory-properties v localname) (unless (tramp-sudoedit-send-command @@ -335,7 +330,6 @@ absolute file names." (defun tramp-sudoedit-handle-delete-file (filename &optional trash) "Like `delete-file' for Tramp files." (with-parsed-tramp-file-name filename nil - (tramp-flush-file-properties v (file-name-directory localname)) (tramp-flush-file-properties v localname) (unless (tramp-sudoedit-send-command @@ -467,7 +461,6 @@ the result will be a local, non-Tramp, file name." (defun tramp-sudoedit-handle-set-file-modes (filename mode) "Like `set-file-modes' for Tramp files." (with-parsed-tramp-file-name filename nil - (tramp-flush-file-properties v (file-name-directory localname)) (tramp-flush-file-properties v localname) (unless (tramp-sudoedit-send-command v "chmod" (format "%o" mode) @@ -526,7 +519,6 @@ the result will be a local, non-Tramp, file name." (defun tramp-sudoedit-handle-set-file-times (filename &optional time) "Like `set-file-times' for Tramp files." (with-parsed-tramp-file-name filename nil - (tramp-flush-file-properties v (file-name-directory localname)) (tramp-flush-file-properties v localname) (let ((time (if (or (null time) @@ -541,34 +533,36 @@ the result will be a local, non-Tramp, file name." (defun tramp-sudoedit-handle-file-truename (filename) "Like `file-truename' for Tramp files." - ;; Preserve trailing "/". + ;; Preserve trailing "/". (funcall - (if (string-equal (file-name-nondirectory filename) "") + (if (tramp-compat-directory-name-p filename) #'file-name-as-directory #'identity) - (with-parsed-tramp-file-name (expand-file-name filename) nil - (tramp-make-tramp-file-name - v - (with-tramp-file-property v localname "file-truename" - (let ((quoted (tramp-compat-file-name-quoted-p localname)) - (localname (tramp-compat-file-name-unquote localname)) - result) - (tramp-message v 4 "Finding true name for `%s'" filename) - (setq result (tramp-sudoedit-send-command-string - v "readlink" "--canonicalize-missing" localname)) - ;; Detect cycle. - (when (and (file-symlink-p filename) - (string-equal result localname)) - (tramp-error - v 'file-error - "Apparent cycle of symbolic links for %s" filename)) - ;; If the resulting localname looks remote, we must quote it - ;; for security reasons. - (when (or quoted (file-remote-p result)) - (let (file-name-handler-alist) - (setq result (tramp-compat-file-name-quote result)))) - (tramp-message v 4 "True name of `%s' is `%s'" localname result) - result)) - 'nohop)))) + ;; Quote properly. + (funcall + (if (tramp-compat-file-name-quoted-p filename) + #'tramp-compat-file-name-quote #'identity) + (with-parsed-tramp-file-name + (tramp-compat-file-name-unquote (expand-file-name filename)) nil + (tramp-make-tramp-file-name + v + (with-tramp-file-property v localname "file-truename" + (let (result) + (tramp-message v 4 "Finding true name for `%s'" filename) + (setq result (tramp-sudoedit-send-command-string + v "readlink" "--canonicalize-missing" localname)) + ;; Detect cycle. + (when (and (file-symlink-p filename) + (string-equal result localname)) + (tramp-error + v 'file-error + "Apparent cycle of symbolic links for %s" filename)) + ;; If the resulting localname looks remote, we must quote it + ;; for security reasons. + (when (file-remote-p result) + (setq result (tramp-compat-file-name-quote result 'top))) + (tramp-message v 4 "True name of `%s' is `%s'" localname result) + result)) + 'nohop))))) (defun tramp-sudoedit-handle-file-writable-p (filename) "Like `file-writable-p' for Tramp files." @@ -617,8 +611,7 @@ component is used as the target of the symlink." ;; If TARGET is still remote, quote it. (if (tramp-tramp-file-p target) - (make-symbolic-link - (let (file-name-handler-alist) (tramp-compat-file-name-quote target)) + (make-symbolic-link (tramp-compat-file-name-quote target 'top) linkname ok-if-already-exists) ;; Do the 'confirm if exists' thing. @@ -634,7 +627,6 @@ component is used as the target of the symlink." (tramp-error v 'file-already-exists localname) (delete-file linkname))) - (tramp-flush-file-properties v (file-name-directory localname)) (tramp-flush-file-properties v localname) (tramp-sudoedit-send-command v "ln" "-sf" diff --git a/tramp.el b/tramp.el index 2556034..4eea312 100644 --- a/tramp.el +++ b/tramp.el @@ -7,7 +7,7 @@ ;; Maintainer: Michael Albinus <michael.albi...@gmx.de> ;; Keywords: comm, processes ;; Package: tramp -;; Version: 2.4.2.1 +;; Version: 2.4.2.2 ;; Package-Requires: ((emacs "24.4")) ;; URL: https://savannah.gnu.org/projects/tramp @@ -1440,7 +1440,7 @@ default values are used." :method method :user user :domain domain :host host :port port :localname localname :hop hop)) ;; The method must be known. - (unless (or (tramp-completion-mode-p) + (unless (or nodefault (tramp-completion-mode-p) (string-equal method tramp-default-method-marker) (assoc method tramp-methods)) (tramp-user-error @@ -2017,13 +2017,11 @@ locally on a remote file name. When the local system is a W32 system but the remote system is Unix, this introduces a superfluous drive letter into the file name. This function removes it." (save-match-data - (funcall - (if (tramp-compat-file-name-quoted-p name) - #'tramp-compat-file-name-quote #'identity) - (let ((name (tramp-compat-file-name-unquote name))) - (if (string-match "\\`[a-zA-Z]:/" name) - (replace-match "/" nil t name) - name))))) + (let ((quoted (tramp-compat-file-name-quoted-p name 'top)) + (result (tramp-compat-file-name-unquote name 'top))) + (setq result (if (string-match "\\`[a-zA-Z]:/" result) + (replace-match "/" nil t result) result)) + (if quoted (tramp-compat-file-name-quote result 'top) result)))) ;;; Config Manipulation Functions: @@ -3046,7 +3044,6 @@ User is always nil." localname))))) (tramp-error v 'file-already-exists newname) (delete-file newname))) - (tramp-flush-file-properties v (file-name-directory localname)) (tramp-flush-file-properties v localname) (copy-file filename newname 'ok-if-already-exists 'keep-time @@ -3328,45 +3325,44 @@ User is always nil." "Like `file-truename' for Tramp files." ;; Preserve trailing "/". (funcall - (if (string-equal (file-name-nondirectory filename) "") + (if (tramp-compat-directory-name-p filename) #'file-name-as-directory #'identity) - (let ((result (expand-file-name filename)) - (numchase 0) - ;; Don't make the following value larger than necessary. - ;; People expect an error message in a timely fashion when - ;; something is wrong; otherwise they might think that Emacs - ;; is hung. Of course, correctness has to come first. - (numchase-limit 20) - symlink-target) - (with-parsed-tramp-file-name result v1 - ;; We cache only the localname. - (tramp-make-tramp-file-name - v1 - (with-tramp-file-property v1 v1-localname "file-truename" - (while (and (setq symlink-target (file-symlink-p result)) - (< numchase numchase-limit)) - (setq numchase (1+ numchase) - result - (with-parsed-tramp-file-name (expand-file-name result) v2 - (tramp-make-tramp-file-name - v2 - (funcall - (if (tramp-compat-file-name-quoted-p v2-localname) - #'tramp-compat-file-name-quote #'identity) - + ;; Quote properly. + (funcall + (if (tramp-compat-file-name-quoted-p filename) + #'tramp-compat-file-name-quote #'identity) + (let ((result (tramp-compat-file-name-unquote (expand-file-name filename))) + (numchase 0) + ;; Don't make the following value larger than necessary. + ;; People expect an error message in a timely fashion when + ;; something is wrong; otherwise they might think that Emacs + ;; is hung. Of course, correctness has to come first. + (numchase-limit 20) + symlink-target) + (with-parsed-tramp-file-name result v1 + ;; We cache only the localname. + (tramp-make-tramp-file-name + v1 + (with-tramp-file-property v1 v1-localname "file-truename" + (while (and (setq symlink-target (file-symlink-p result)) + (< numchase numchase-limit)) + (setq numchase (1+ numchase) + result + (with-parsed-tramp-file-name (expand-file-name result) v2 + (tramp-make-tramp-file-name + v2 (if (stringp symlink-target) (if (file-remote-p symlink-target) - (let (file-name-handler-alist) - (tramp-compat-file-name-quote symlink-target)) + (tramp-compat-file-name-quote symlink-target 'top) (expand-file-name symlink-target (file-name-directory v2-localname))) - v2-localname)) - 'nohop))) - (when (>= numchase numchase-limit) - (tramp-error - v1 'file-error - "Maximum number (%d) of symlinks exceeded" numchase-limit))) - (tramp-compat-file-local-name (directory-file-name result)))))))) + v2-localname) + 'nohop))) + (when (>= numchase numchase-limit) + (tramp-error + v1 'file-error + "Maximum number (%d) of symlinks exceeded" numchase-limit))) + (tramp-compat-file-local-name (directory-file-name result))))))))) (defun tramp-handle-file-writable-p (filename) "Like `file-writable-p' for Tramp files." @@ -3401,7 +3397,7 @@ User is always nil." "Like `insert-directory' for Tramp files." (unless switches (setq switches "")) ;; Mark trailing "/". - (when (and (zerop (length (file-name-nondirectory filename))) + (when (and (tramp-compat-directory-name-p filename) (not full-directory-p)) (setq switches (concat switches "F"))) ;; Check, whether directory is accessible. @@ -3812,9 +3808,16 @@ of." (format "File %s exists; overwrite anyway? " filename))))) (tramp-error v 'file-already-exists filename)) - (let ((tmpfile (tramp-compat-make-temp-file filename))) + (let ((tmpfile (tramp-compat-make-temp-file filename)) + (modes (save-excursion (tramp-default-file-modes filename)))) (when (and append (file-exists-p filename)) (copy-file filename tmpfile 'ok)) + ;; The permissions of the temporary file should be set. If + ;; FILENAME does not exist (eq modes nil) it has been + ;; renamed to the backup file. This case `save-buffer' + ;; handles permissions. + ;; Ensure that it is still readable. + (set-file-modes tmpfile (logior (or modes 0) #o0400)) ;; We say `no-message' here because we don't want the visited file ;; modtime data to be clobbered from the temp file. We call ;; `set-visited-file-modtime' ourselves later on. @@ -3827,7 +3830,6 @@ of." (tramp-error v 'file-error "Couldn't write region to `%s'" filename)))) - (tramp-flush-file-properties v (file-name-directory localname)) (tramp-flush-file-properties v localname) ;; Set file modification time. diff --git a/tramp.info b/tramp.info index 2024eca..bd26ec5 100644 --- a/tramp.info +++ b/tramp.info @@ -21,10 +21,10 @@ END-INFO-DIR-ENTRY File: tramp.info, Node: Top, Next: Overview, Prev: (dir), Up: (dir) -TRAMP 2.4.2.1 User Manual +TRAMP 2.4.2.2 User Manual ************************* -This file documents TRAMP 2.4.2.1, a remote file editing package for +This file documents TRAMP 2.4.2.2, a remote file editing package for Emacs. TRAMP stands for “Transparent Remote (file) Access, Multiple @@ -87,7 +87,7 @@ Configuring TRAMP for use * Connection types:: Types of connections to remote hosts. * Inline methods:: Inline methods. * External methods:: External methods. -* GVFS based methods:: GVFS based external methods. +* GVFS-based methods:: GVFS-based external methods. * Default Method:: Selecting a default method. * Default User:: Selecting a default user. * Default Host:: Selecting a default host. @@ -399,9 +399,9 @@ name is the share exported by the remote host, ‘path’ in this example. 3.7 Using GVFS-based methods ============================ -On systems, which have installed the virtual file system for the GNOME -Desktop (GVFS), its offered methods could be used by TRAMP. Examples -are ‘/sftp:user@host:/path/to/file’, ‘/afp:user@host:/path/to/file’ +On systems, which have installed GVFS (the GNOME Virtual File System), +its offered methods could be used by TRAMP. Examples are +‘/sftp:user@host:/path/to/file’, ‘/afp:user@host:/path/to/file’ (accessing Apple’s AFP file system), ‘/dav:user@host:/path/to/file’ and ‘/davs:user@host:/path/to/file’ (for WebDAV shares). @@ -464,7 +464,7 @@ used in your init file: * Connection types:: Types of connections to remote hosts. * Inline methods:: Inline methods. * External methods:: External methods. -* GVFS based methods:: GVFS based external methods. +* GVFS-based methods:: GVFS-based external methods. * Default Method:: Selecting a default method. Here we also try to help those who don’t have the foggiest which method @@ -643,7 +643,7 @@ the availability and usability of one of the commands defined in session. -File: tramp.info, Node: External methods, Next: GVFS based methods, Prev: Inline methods, Up: Configuration +File: tramp.info, Node: External methods, Next: GVFS-based methods, Prev: Inline methods, Up: Configuration 4.3 External methods ==================== @@ -881,16 +881,16 @@ files smaller than ‘tramp-copy-size-limit’ still use inline methods. ‘moveto-args’. Access via ‘rclone’ is slow. If you have an alternative method for - accessing the system storage, you shall prefer this. *note GVFS - based methods:: for example, methods ‘gdrive’ and ‘nextcloud’. + accessing the system storage, you shall prefer this. *note + GVFS-based methods:: for example, methods ‘gdrive’ and ‘nextcloud’. *Note*: The ‘rclone’ method is experimental, don’t use it in production systems! -File: tramp.info, Node: GVFS based methods, Next: Default Method, Prev: External methods, Up: Configuration +File: tramp.info, Node: GVFS-based methods, Next: Default Method, Prev: External methods, Up: Configuration -4.4 GVFS based external methods +4.4 GVFS-based external methods =============================== GVFS is the virtual file system for the GNOME Desktop, @@ -952,11 +952,19 @@ have the message bus system, D-Bus integration active, *note D-Bus: default, this list includes ‘afp’, ‘dav’, ‘davs’, ‘gdrive’, ‘nextcloud’ and ‘sftp’. Other methods to include are ‘ftp’, ‘http’, ‘https’ and ‘smb’. These methods are not intended to be - used directly as GVFS based method. Instead, they are added here + used directly as GVFS-based method. Instead, they are added here for the benefit of *note Archive file names::. + If you want to use GVFS-based ‘ftp’ or ‘smb’ methods, you must add + them to ‘tramp-gvfs-methods’, and you must disable the + corresponding Tramp package by setting ‘tramp-ftp-method’ or + ‘tramp-smb-method’ to ‘nil’, respectively: + + (add-to-list 'tramp-gvfs-methods "ftp") + (customize-set-variable 'tramp-ftp-method nil) + -File: tramp.info, Node: Default Method, Next: Default User, Prev: GVFS based methods, Up: Configuration +File: tramp.info, Node: Default Method, Next: Default User, Prev: GVFS-based methods, Up: Configuration 4.5 Selecting a default method ============================== @@ -2199,7 +2207,7 @@ the variable ‘default-directory’ is remote: (start-file-process "grep" (get-buffer-create "*grep*") "/bin/sh" "-c" "grep -e tramp *")) - Remote processes do not apply to GVFS (see *note GVFS based + Remote processes do not apply to GVFS (see *note GVFS-based methods::) because the remote file system is mounted on the local host and TRAMP just accesses by changing the ‘default-directory’. @@ -2477,9 +2485,9 @@ File: tramp.info, Node: Archive file names, Prev: Cleanup remote connections, ====================== TRAMP offers also transparent access to files inside file archives. -This is possible only on machines which have installed the virtual file -system for the GNOME Desktop (GVFS), *note GVFS based methods::. -Internally, file archives are mounted via the GVFS ‘archive’ method. +This is possible only on machines which have installed GVFS (the GNOME +Virtual File System), *note GVFS-based methods::. Internally, file +archives are mounted via the GVFS ‘archive’ method. A file archive is a regular file of kind ‘/path/to/dir/file.EXT’. The extension ‘.EXT’ identifies the type of the file archive. A file @@ -3969,7 +3977,7 @@ Variable Index * tramp-default-user-alist: Default User. (line 14) * tramp-file-name-regexp: Change file name syntax. (line 28) -* tramp-gvfs-methods: GVFS based methods. (line 60) +* tramp-gvfs-methods: GVFS-based methods. (line 60) * tramp-histfile-override: Frequently Asked Questions. (line 277) * tramp-ignored-file-name-regexp: Frequently Asked Questions. @@ -4017,7 +4025,7 @@ Concept Index * adb method: Quick Start Guide. (line 115) * adb method <1>: External methods. (line 181) * afp method: Quick Start Guide. (line 95) -* afp method <1>: GVFS based methods. (line 16) +* afp method <1>: GVFS-based methods. (line 16) * alternative file name syntax: Change file name syntax. (line 6) * android: Quick Start Guide. (line 115) @@ -4055,10 +4063,10 @@ Concept Index * cygwin and ssh-agent: Windows setup hints. (line 29) * cygwin, issues: Windows setup hints. (line 6) * dav method: Quick Start Guide. (line 95) -* dav method <1>: GVFS based methods. (line 24) +* dav method <1>: GVFS-based methods. (line 24) * davs method: Quick Start Guide. (line 95) -* davs method <1>: GVFS based methods. (line 24) -* dbus: GVFS based methods. (line 6) +* davs method <1>: GVFS-based methods. (line 24) +* dbus: GVFS-based methods. (line 6) * deb file archive suffix: Archive file names. (line 43) * default configuration: Configuration. (line 6) * default host: Default Host. (line 6) @@ -4126,16 +4134,16 @@ Concept Index * ftp method: External methods. (line 115) * gdb: Remote processes. (line 208) * gdrive method: Quick Start Guide. (line 104) -* gdrive method <1>: GVFS based methods. (line 34) +* gdrive method <1>: GVFS-based methods. (line 34) * git method: Customizing Methods. (line 37) * GNOME Online Accounts: Quick Start Guide. (line 104) -* GNOME Online Accounts <1>: GVFS based methods. (line 47) +* GNOME Online Accounts <1>: GVFS-based methods. (line 47) * GNU ELPA: Obtaining TRAMP. (line 6) * google drive: Quick Start Guide. (line 104) -* google drive <1>: GVFS based methods. (line 34) +* google drive <1>: GVFS-based methods. (line 34) * gud.el: Remote processes. (line 208) -* gvfs based methods: Quick Start Guide. (line 95) -* gvfs based methods <1>: GVFS based methods. (line 6) +* gvfs-based methods: Quick Start Guide. (line 95) +* gvfs-based methods <1>: GVFS-based methods. (line 6) * hdfs method: Customizing Methods. (line 43) * how it works: Overview. (line 44) * http tunnel: Firewalls. (line 6) @@ -4154,19 +4162,19 @@ Concept Index * method adb: Quick Start Guide. (line 115) * method adb <1>: External methods. (line 181) * method afp: Quick Start Guide. (line 95) -* method afp <1>: GVFS based methods. (line 16) +* method afp <1>: GVFS-based methods. (line 16) * method archive: Archive file names. (line 6) * method dav: Quick Start Guide. (line 95) -* method dav <1>: GVFS based methods. (line 24) +* method dav <1>: GVFS-based methods. (line 24) * method davs: Quick Start Guide. (line 95) -* method davs <1>: GVFS based methods. (line 24) +* method davs <1>: GVFS-based methods. (line 24) * method doas: Inline methods. (line 68) * method docker: Customizing Methods. (line 15) * method fcp: External methods. (line 73) * method fsh: External methods. (line 83) * method ftp: External methods. (line 115) * method gdrive: Quick Start Guide. (line 104) -* method gdrive <1>: GVFS based methods. (line 34) +* method gdrive <1>: GVFS-based methods. (line 34) * method git: Customizing Methods. (line 37) * method hdfs: Customizing Methods. (line 43) * method krlogin: Inline methods. (line 100) @@ -4176,7 +4184,7 @@ Concept Index * method lxd: Customizing Methods. (line 32) * method nc: External methods. (line 88) * method nextcloud: Quick Start Guide. (line 104) -* method nextcloud <1>: GVFS based methods. (line 47) +* method nextcloud <1>: GVFS-based methods. (line 47) * method plink: Quick Start Guide. (line 44) * method plink <1>: Quick Start Guide. (line 68) * method plink <2>: Inline methods. (line 110) @@ -4192,7 +4200,7 @@ Concept Index * method scpx: External methods. (line 48) * method scpx with cygwin: Windows setup hints. (line 21) * method sftp: Quick Start Guide. (line 95) -* method sftp <1>: GVFS based methods. (line 55) +* method sftp <1>: GVFS-based methods. (line 55) * method sg: Quick Start Guide. (line 56) * method sg <1>: Inline methods. (line 74) * method smb: Quick Start Guide. (line 87) @@ -4214,7 +4222,7 @@ Concept Index * method vagrant: Customizing Methods. (line 48) * methods, external: External methods. (line 6) * methods, gvfs: Quick Start Guide. (line 95) -* methods, gvfs <1>: GVFS based methods. (line 6) +* methods, gvfs <1>: GVFS-based methods. (line 6) * methods, inline: Inline methods. (line 6) * ms windows (with smb method): Quick Start Guide. (line 87) * ms windows (with smb method) <1>: External methods. (line 121) @@ -4226,9 +4234,9 @@ Concept Index * nc method: External methods. (line 88) * nc unix command: Remote shell setup. (line 180) * nextcloud: Quick Start Guide. (line 104) -* nextcloud <1>: GVFS based methods. (line 47) +* nextcloud <1>: GVFS-based methods. (line 47) * nextcloud method: Quick Start Guide. (line 104) -* nextcloud method <1>: GVFS based methods. (line 47) +* nextcloud method <1>: GVFS-based methods. (line 47) * obtaining TRAMP: Obtaining TRAMP. (line 6) * odb file archive suffix: Archive file names. (line 60) * odf file archive suffix: Archive file names. (line 60) @@ -4273,7 +4281,7 @@ Concept Index * separate syntax: Change file name syntax. (line 21) * sftp method: Quick Start Guide. (line 95) -* sftp method <1>: GVFS based methods. (line 55) +* sftp method <1>: GVFS-based methods. (line 55) * sg method: Quick Start Guide. (line 56) * sg method <1>: Inline methods. (line 74) * shar file archive suffix: Archive file names. (line 68) @@ -4343,50 +4351,50 @@ Ref: Quick Start Guide: ssh, plink, su, sudo and sg methods16134 Ref: Quick Start Guide: sudoedit method16664 Ref: Quick Start Guide: smb method17075 Ref: Quick Start Guide: GVFS-based methods17406 -Ref: Quick Start Guide: GNOME Online Accounts based methods17818 -Ref: Quick Start Guide: Android18360 -Ref: Quick Start Guide: rclone method18592 -Node: Configuration18919 -Node: Connection types21391 -Node: Inline methods22805 -Node: External methods27572 -Node: GVFS based methods38091 -Node: Default Method40981 -Node: Default User43998 -Node: Default Host45521 -Node: Multi-hops46653 -Node: Firewalls50845 -Node: Customizing Methods52302 -Node: Customizing Completion54642 -Node: Password handling58132 -Ref: Using an authentication file58602 -Ref: Caching passwords60104 -Node: Connection caching60622 -Node: Predefined connection information61552 -Node: Remote programs63897 -Node: Remote shell setup66818 -Node: Android shell setup75028 -Node: Auto-save and Backup77415 -Node: Windows setup hints80490 -Node: Usage82110 -Node: File name syntax83408 -Node: Change file name syntax85415 -Node: File name completion86846 -Node: Ad-hoc multi-hops89919 -Node: Remote processes91985 -Ref: Running a debugger on a remote host100743 -Node: Cleanup remote connections102713 -Node: Archive file names104247 -Node: Bug Reports108635 -Node: Frequently Asked Questions111017 -Node: Files directories and localnames133301 -Node: Localname deconstruction133737 -Node: External packages134390 -Node: Traces and Profiles136435 -Node: GNU Free Documentation License138404 -Node: Function Index163775 -Node: Variable Index166379 -Node: Concept Index173568 +Ref: Quick Start Guide: GNOME Online Accounts based methods17802 +Ref: Quick Start Guide: Android18344 +Ref: Quick Start Guide: rclone method18576 +Node: Configuration18903 +Node: Connection types21375 +Node: Inline methods22789 +Node: External methods27556 +Node: GVFS-based methods38075 +Node: Default Method41344 +Node: Default User44361 +Node: Default Host45884 +Node: Multi-hops47016 +Node: Firewalls51208 +Node: Customizing Methods52665 +Node: Customizing Completion55005 +Node: Password handling58495 +Ref: Using an authentication file58965 +Ref: Caching passwords60467 +Node: Connection caching60985 +Node: Predefined connection information61915 +Node: Remote programs64260 +Node: Remote shell setup67181 +Node: Android shell setup75391 +Node: Auto-save and Backup77778 +Node: Windows setup hints80853 +Node: Usage82473 +Node: File name syntax83771 +Node: Change file name syntax85778 +Node: File name completion87209 +Node: Ad-hoc multi-hops90282 +Node: Remote processes92348 +Ref: Running a debugger on a remote host101106 +Node: Cleanup remote connections103076 +Node: Archive file names104610 +Node: Bug Reports108983 +Node: Frequently Asked Questions111365 +Node: Files directories and localnames133649 +Node: Localname deconstruction134085 +Node: External packages134738 +Node: Traces and Profiles136783 +Node: GNU Free Documentation License138752 +Node: Function Index164123 +Node: Variable Index166727 +Node: Concept Index173916 End Tag Table diff --git a/trampver.el b/trampver.el index 05b5965..80aa3eb 100644 --- a/trampver.el +++ b/trampver.el @@ -31,7 +31,7 @@ ;; aclocal.m4; should be changed only there. ;;;###tramp-autoload -(defconst tramp-version "2.4.2.1" +(defconst tramp-version "2.4.2.2" "This version of Tramp.") ;;;###tramp-autoload @@ -65,7 +65,7 @@ ;; Check for Emacs version. (let ((x (if (not (string-lessp emacs-version "24.4")) "ok" - (format "Tramp 2.4.2.1 is not fit for %s" + (format "Tramp 2.4.2.2 is not fit for %s" (replace-regexp-in-string "\n" "" (emacs-version)))))) (unless (string-equal "ok" x) (error "%s" x)))