diff options
| author | Michael Albinus | 2025-03-16 14:17:38 +0100 |
|---|---|---|
| committer | Michael Albinus | 2025-03-16 14:17:38 +0100 |
| commit | b8104dadbf285d12c356d4cddd28ac3eaf05f263 (patch) | |
| tree | fdee9ed3209a12b0957d4a7699db51e0e2d05e8e | |
| parent | 03e33cbef3e33aa1ec843388d1671f7116a7347b (diff) | |
| download | emacs-b8104dadbf285d12c356d4cddd28ac3eaf05f263.tar.gz emacs-b8104dadbf285d12c356d4cddd28ac3eaf05f263.zip | |
Tramp: Handle symlinks to non-existing targets better
* lisp/net/tramp-gvfs.el (tramp-gvfs-do-copy-or-rename-file):
Don't use the truename.
* lisp/net/tramp-sh.el (tramp-do-copy-or-rename-file): Refactor. Handle
symlinks. (Bug#76678)
* lisp/net/tramp-smb.el (tramp-smb-errors): Add string.
(tramp-smb-handle-copy-file, tramp-smb-handle-rename-file):
Refactor.
* lisp/net/tramp-sudoedit.el (tramp-sudoedit-do-copy-or-rename-file):
Don't use the truename. Handle symlinks.
* lisp/net/tramp.el (tramp-barf-if-file-missing): Accept also symlinks.
(tramp-skeleton-file-exists-p): Handle non-existing symlink targets.
(tramp-skeleton-set-file-modes-times-uid-gid): Fix typo.
* test/lisp/net/tramp-tests.el (vc-handled-backends):
Suppress only if noninteractive.
(tramp-test11-copy-file, tramp-test12-rename-file)
(tramp-test18-file-attributes, tramp-test21-file-links)
(tramp--test-check-files): Adapt tests.
| -rw-r--r-- | lisp/net/tramp-adb.el | 2 | ||||
| -rw-r--r-- | lisp/net/tramp-cmds.el | 1 | ||||
| -rw-r--r-- | lisp/net/tramp-gvfs.el | 6 | ||||
| -rw-r--r-- | lisp/net/tramp-sh.el | 234 | ||||
| -rw-r--r-- | lisp/net/tramp-smb.el | 191 | ||||
| -rw-r--r-- | lisp/net/tramp-sudoedit.el | 152 | ||||
| -rw-r--r-- | lisp/net/tramp.el | 21 | ||||
| -rw-r--r-- | test/lisp/net/tramp-tests.el | 89 |
8 files changed, 385 insertions, 311 deletions
diff --git a/lisp/net/tramp-adb.el b/lisp/net/tramp-adb.el index f3b4e547692..fb54abfa0c6 100644 --- a/lisp/net/tramp-adb.el +++ b/lisp/net/tramp-adb.el | |||
| @@ -997,7 +997,7 @@ error and non-nil on success." | |||
| 997 | ;; <https://android.stackexchange.com/questions/226638/how-to-use-multibyte-file-names-in-adb-shell/232379#232379> | 997 | ;; <https://android.stackexchange.com/questions/226638/how-to-use-multibyte-file-names-in-adb-shell/232379#232379> |
| 998 | ;; mksh uses UTF-8 internally, but is currently limited to the | 998 | ;; mksh uses UTF-8 internally, but is currently limited to the |
| 999 | ;; BMP (basic multilingua plane), which means U+0000 to | 999 | ;; BMP (basic multilingua plane), which means U+0000 to |
| 1000 | ;; U+FFFD. If you want to use SMP codepoints (U-00010000 to | 1000 | ;; U+FFFD. If you want to use SMP codepoints (U-00010000 to |
| 1001 | ;; U-0010FFFD) on the input line, you currently have to disable | 1001 | ;; U-0010FFFD) on the input line, you currently have to disable |
| 1002 | ;; the UTF-8 mode (sorry). | 1002 | ;; the UTF-8 mode (sorry). |
| 1003 | (tramp-adb-execute-adb-command vec "shell" command) | 1003 | (tramp-adb-execute-adb-command vec "shell" command) |
diff --git a/lisp/net/tramp-cmds.el b/lisp/net/tramp-cmds.el index 0118ed7ab4c..0d90382b2d3 100644 --- a/lisp/net/tramp-cmds.el +++ b/lisp/net/tramp-cmds.el | |||
| @@ -738,6 +738,7 @@ By default this is done using the \"sudo\" Tramp method. | |||
| 738 | YOu can customize `tramp-file-name-with-method' to change this. | 738 | YOu can customize `tramp-file-name-with-method' to change this. |
| 739 | 739 | ||
| 740 | Interactively, with a prefix argument, prompt for a different method." | 740 | Interactively, with a prefix argument, prompt for a different method." |
| 741 | ;; (declare (completion tramp-dired-buffer-command-completion-p)) | ||
| 741 | (interactive) | 742 | (interactive) |
| 742 | (with-tramp-file-name-with-method | 743 | (with-tramp-file-name-with-method |
| 743 | (find-file (tramp-file-name-with-sudo (dired-get-file-for-visit))))) | 744 | (find-file (tramp-file-name-with-sudo (dired-get-file-for-visit))))) |
diff --git a/lisp/net/tramp-gvfs.el b/lisp/net/tramp-gvfs.el index 2f0593b0a93..eff7a2d9ff8 100644 --- a/lisp/net/tramp-gvfs.el +++ b/lisp/net/tramp-gvfs.el | |||
| @@ -1044,7 +1044,9 @@ file names." | |||
| 1044 | (unless (memq op '(copy rename)) | 1044 | (unless (memq op '(copy rename)) |
| 1045 | (error "Unknown operation `%s', must be `copy' or `rename'" op)) | 1045 | (error "Unknown operation `%s', must be `copy' or `rename'" op)) |
| 1046 | 1046 | ||
| 1047 | (setq filename (file-truename filename)) | 1047 | ;; We cannot use `file-truename', this would fail for symlinks with |
| 1048 | ;; non-existing target. | ||
| 1049 | (setq filename (expand-file-name filename)) | ||
| 1048 | (if (file-directory-p filename) | 1050 | (if (file-directory-p filename) |
| 1049 | (progn | 1051 | (progn |
| 1050 | (copy-directory filename newname keep-date t) | 1052 | (copy-directory filename newname keep-date t) |
| @@ -2217,7 +2219,7 @@ connection if a previous connection has died for some reason." | |||
| 2217 | method '(("smb" . "smb-share") | 2219 | method '(("smb" . "smb-share") |
| 2218 | ("davs" . "dav") | 2220 | ("davs" . "dav") |
| 2219 | ("nextcloud" . "dav") | 2221 | ("nextcloud" . "dav") |
| 2220 | ("afp". "afp-volume") | 2222 | ("afp" . "afp-volume") |
| 2221 | ("gdrive" . "google-drive"))) | 2223 | ("gdrive" . "google-drive"))) |
| 2222 | method) | 2224 | method) |
| 2223 | tramp-gvfs-mounttypes) | 2225 | tramp-gvfs-mounttypes) |
diff --git a/lisp/net/tramp-sh.el b/lisp/net/tramp-sh.el index 84b0d97cd20..2b113ba1acf 100644 --- a/lisp/net/tramp-sh.el +++ b/lisp/net/tramp-sh.el | |||
| @@ -2128,123 +2128,129 @@ file names." | |||
| 2128 | (progn | 2128 | (progn |
| 2129 | (copy-directory filename newname keep-date t) | 2129 | (copy-directory filename newname keep-date t) |
| 2130 | (when (eq op 'rename) (delete-directory filename 'recursive))) | 2130 | (when (eq op 'rename) (delete-directory filename 'recursive))) |
| 2131 | (if (file-symlink-p filename) | ||
| 2132 | (progn | ||
| 2133 | (make-symbolic-link | ||
| 2134 | (file-symlink-p filename) newname ok-if-already-exists) | ||
| 2135 | (when (eq op 'rename) (delete-file filename))) | ||
| 2136 | |||
| 2137 | ;; FIXME: This should be optimized. Computing `file-attributes' | ||
| 2138 | ;; checks already, whether the file exists. | ||
| 2139 | (let ((t1 (tramp-tramp-file-p filename)) | ||
| 2140 | (t2 (tramp-tramp-file-p newname)) | ||
| 2141 | (length (or (file-attribute-size | ||
| 2142 | (file-attributes (file-truename filename))) | ||
| 2143 | ;; `filename' doesn't exist, for example due | ||
| 2144 | ;; to non-existent symlink target. | ||
| 2145 | 0)) | ||
| 2146 | (file-times (file-attribute-modification-time | ||
| 2147 | (file-attributes filename))) | ||
| 2148 | (file-modes (tramp-default-file-modes filename)) | ||
| 2149 | (msg-operation (if (eq op 'copy) "Copying" "Renaming")) | ||
| 2150 | copy-keep-date) | ||
| 2151 | |||
| 2152 | (with-parsed-tramp-file-name (if t1 filename newname) nil | ||
| 2153 | (tramp-barf-if-file-missing v filename | ||
| 2154 | (when (and (not ok-if-already-exists) (file-exists-p newname)) | ||
| 2155 | (tramp-error v 'file-already-exists newname)) | ||
| 2156 | (when (and (file-directory-p newname) | ||
| 2157 | (not (directory-name-p newname))) | ||
| 2158 | (tramp-error v 'file-error "File is a directory %s" newname)) | ||
| 2131 | 2159 | ||
| 2132 | ;; FIXME: This should be optimized. Computing `file-attributes' | 2160 | (with-tramp-progress-reporter |
| 2133 | ;; checks already, whether the file exists. | 2161 | v 0 (format "%s %s to %s" msg-operation filename newname) |
| 2134 | (let ((t1 (tramp-tramp-file-p filename)) | ||
| 2135 | (t2 (tramp-tramp-file-p newname)) | ||
| 2136 | (length (file-attribute-size | ||
| 2137 | (file-attributes (file-truename filename)))) | ||
| 2138 | (file-times (file-attribute-modification-time | ||
| 2139 | (file-attributes filename))) | ||
| 2140 | (file-modes (tramp-default-file-modes filename)) | ||
| 2141 | (msg-operation (if (eq op 'copy) "Copying" "Renaming")) | ||
| 2142 | copy-keep-date) | ||
| 2143 | |||
| 2144 | (with-parsed-tramp-file-name (if t1 filename newname) nil | ||
| 2145 | (unless length | ||
| 2146 | (tramp-error v 'file-missing filename)) | ||
| 2147 | (tramp-barf-if-file-missing v filename | ||
| 2148 | (when (and (not ok-if-already-exists) (file-exists-p newname)) | ||
| 2149 | (tramp-error v 'file-already-exists newname)) | ||
| 2150 | (when (and (file-directory-p newname) | ||
| 2151 | (not (directory-name-p newname))) | ||
| 2152 | (tramp-error v 'file-error "File is a directory %s" newname)) | ||
| 2153 | |||
| 2154 | (with-tramp-progress-reporter | ||
| 2155 | v 0 (format "%s %s to %s" msg-operation filename newname) | ||
| 2156 | 2162 | ||
| 2157 | (cond | ||
| 2158 | ;; Both are Tramp files. | ||
| 2159 | ((and t1 t2) | ||
| 2160 | (with-parsed-tramp-file-name filename v1 | ||
| 2161 | (with-parsed-tramp-file-name newname v2 | ||
| 2162 | (cond | ||
| 2163 | ;; Shortcut: if method, host, user are the same for | ||
| 2164 | ;; both files, we invoke `cp' or `mv' on the remote | ||
| 2165 | ;; host directly. | ||
| 2166 | ((tramp-equal-remote filename newname) | ||
| 2167 | (setq copy-keep-date | ||
| 2168 | (or (eq op 'rename) keep-date preserve-uid-gid)) | ||
| 2169 | (tramp-do-copy-or-rename-file-directly | ||
| 2170 | op filename newname | ||
| 2171 | ok-if-already-exists keep-date preserve-uid-gid)) | ||
| 2172 | |||
| 2173 | ;; Try out-of-band operation. | ||
| 2174 | ((and | ||
| 2175 | (tramp-method-out-of-band-p v1 length) | ||
| 2176 | (tramp-method-out-of-band-p v2 length)) | ||
| 2177 | (setq copy-keep-date | ||
| 2178 | (tramp-get-method-parameter v 'tramp-copy-keep-date)) | ||
| 2179 | (tramp-do-copy-or-rename-file-out-of-band | ||
| 2180 | op filename newname ok-if-already-exists keep-date)) | ||
| 2181 | |||
| 2182 | ;; No shortcut was possible. So we copy the file | ||
| 2183 | ;; first. If the operation was `rename', we go | ||
| 2184 | ;; back and delete the original file (if the copy | ||
| 2185 | ;; was successful). The approach is simple-minded: | ||
| 2186 | ;; we create a new buffer, insert the contents of | ||
| 2187 | ;; the source file into it, then write out the | ||
| 2188 | ;; buffer to the target file. The advantage is | ||
| 2189 | ;; that it doesn't matter which file name handlers | ||
| 2190 | ;; are used for the source and target file. | ||
| 2191 | (t | ||
| 2192 | (tramp-do-copy-or-rename-file-via-buffer | ||
| 2193 | op filename newname ok-if-already-exists keep-date)))))) | ||
| 2194 | |||
| 2195 | ;; One file is a Tramp file, the other one is local. | ||
| 2196 | ((or t1 t2) | ||
| 2197 | (cond | 2163 | (cond |
| 2198 | ;; Fast track on local machine. | 2164 | ;; Both are Tramp files. |
| 2199 | ((tramp-local-host-p v) | 2165 | ((and t1 t2) |
| 2200 | (setq copy-keep-date | 2166 | (with-parsed-tramp-file-name filename v1 |
| 2201 | (or (eq op 'rename) keep-date preserve-uid-gid)) | 2167 | (with-parsed-tramp-file-name newname v2 |
| 2202 | (tramp-do-copy-or-rename-file-directly | 2168 | (cond |
| 2203 | op filename newname | 2169 | ;; Shortcut: if method, host, user are the same |
| 2204 | ok-if-already-exists keep-date preserve-uid-gid)) | 2170 | ;; for both files, we invoke `cp' or `mv' on the |
| 2205 | 2171 | ;; remote host directly. | |
| 2206 | ;; If the Tramp file has an out-of-band method, the | 2172 | ((tramp-equal-remote filename newname) |
| 2207 | ;; corresponding copy-program can be invoked. | 2173 | (setq copy-keep-date |
| 2208 | ((tramp-method-out-of-band-p v length) | 2174 | (or (eq op 'rename) keep-date preserve-uid-gid)) |
| 2209 | (setq copy-keep-date | 2175 | (tramp-do-copy-or-rename-file-directly |
| 2210 | (tramp-get-method-parameter v 'tramp-copy-keep-date)) | 2176 | op filename newname |
| 2211 | (tramp-do-copy-or-rename-file-out-of-band | 2177 | ok-if-already-exists keep-date preserve-uid-gid)) |
| 2212 | op filename newname ok-if-already-exists keep-date)) | 2178 | |
| 2179 | ;; Try out-of-band operation. | ||
| 2180 | ((and | ||
| 2181 | (tramp-method-out-of-band-p v1 length) | ||
| 2182 | (tramp-method-out-of-band-p v2 length)) | ||
| 2183 | (setq copy-keep-date | ||
| 2184 | (tramp-get-method-parameter v 'tramp-copy-keep-date)) | ||
| 2185 | (tramp-do-copy-or-rename-file-out-of-band | ||
| 2186 | op filename newname ok-if-already-exists keep-date)) | ||
| 2187 | |||
| 2188 | ;; No shortcut was possible. So we copy the file | ||
| 2189 | ;; first. If the operation was `rename', we go | ||
| 2190 | ;; back and delete the original file (if the copy | ||
| 2191 | ;; was successful). The approach is simple-minded: | ||
| 2192 | ;; we create a new buffer, insert the contents of | ||
| 2193 | ;; the source file into it, then write out the | ||
| 2194 | ;; buffer to the target file. The advantage is | ||
| 2195 | ;; that it doesn't matter which file name handlers | ||
| 2196 | ;; are used for the source and target file. | ||
| 2197 | (t | ||
| 2198 | (tramp-do-copy-or-rename-file-via-buffer | ||
| 2199 | op filename newname ok-if-already-exists keep-date)))))) | ||
| 2200 | |||
| 2201 | ;; One file is a Tramp file, the other one is local. | ||
| 2202 | ((or t1 t2) | ||
| 2203 | (cond | ||
| 2204 | ;; Fast track on local machine. | ||
| 2205 | ((tramp-local-host-p v) | ||
| 2206 | (setq copy-keep-date | ||
| 2207 | (or (eq op 'rename) keep-date preserve-uid-gid)) | ||
| 2208 | (tramp-do-copy-or-rename-file-directly | ||
| 2209 | op filename newname | ||
| 2210 | ok-if-already-exists keep-date preserve-uid-gid)) | ||
| 2211 | |||
| 2212 | ;; If the Tramp file has an out-of-band method, the | ||
| 2213 | ;; corresponding copy-program can be invoked. | ||
| 2214 | ((tramp-method-out-of-band-p v length) | ||
| 2215 | (setq copy-keep-date | ||
| 2216 | (tramp-get-method-parameter v 'tramp-copy-keep-date)) | ||
| 2217 | (tramp-do-copy-or-rename-file-out-of-band | ||
| 2218 | op filename newname ok-if-already-exists keep-date)) | ||
| 2219 | |||
| 2220 | ;; Use the inline method via a Tramp buffer. | ||
| 2221 | (t (tramp-do-copy-or-rename-file-via-buffer | ||
| 2222 | op filename newname ok-if-already-exists keep-date)))) | ||
| 2223 | |||
| 2224 | (t | ||
| 2225 | ;; One of them must be a Tramp file. | ||
| 2226 | (error "Tramp implementation says this cannot happen"))) | ||
| 2227 | |||
| 2228 | ;; In case of `rename', we must flush the cache of the source file. | ||
| 2229 | (when (and t1 (eq op 'rename)) | ||
| 2230 | (with-parsed-tramp-file-name filename v1 | ||
| 2231 | (tramp-flush-file-properties v1 v1-localname))) | ||
| 2232 | |||
| 2233 | ;; NEWNAME has wrong cached values. | ||
| 2234 | (when t2 | ||
| 2235 | (with-parsed-tramp-file-name newname v2 | ||
| 2236 | (tramp-flush-file-properties v2 v2-localname))) | ||
| 2213 | 2237 | ||
| 2214 | ;; Use the inline method via a Tramp buffer. | 2238 | ;; Handle `preserve-extended-attributes'. We ignore |
| 2215 | (t (tramp-do-copy-or-rename-file-via-buffer | 2239 | ;; possible errors, because ACL strings could be |
| 2216 | op filename newname ok-if-already-exists keep-date)))) | 2240 | ;; incompatible. |
| 2241 | (when-let* ((attributes (and preserve-extended-attributes | ||
| 2242 | (file-extended-attributes filename)))) | ||
| 2243 | (ignore-errors | ||
| 2244 | (set-file-extended-attributes newname attributes))) | ||
| 2217 | 2245 | ||
| 2218 | (t | 2246 | ;; KEEP-DATE handling. |
| 2219 | ;; One of them must be a Tramp file. | 2247 | (when (and keep-date (not copy-keep-date)) |
| 2220 | (error "Tramp implementation says this cannot happen"))) | 2248 | (set-file-times |
| 2221 | 2249 | newname file-times (unless ok-if-already-exists 'nofollow))) | |
| 2222 | ;; In case of `rename', we must flush the cache of the source file. | 2250 | |
| 2223 | (when (and t1 (eq op 'rename)) | 2251 | ;; Set the mode. |
| 2224 | (with-parsed-tramp-file-name filename v1 | 2252 | (unless (and keep-date copy-keep-date) |
| 2225 | (tramp-flush-file-properties v1 v1-localname))) | 2253 | (set-file-modes newname file-modes))))))))) |
| 2226 | |||
| 2227 | ;; NEWNAME has wrong cached values. | ||
| 2228 | (when t2 | ||
| 2229 | (with-parsed-tramp-file-name newname v2 | ||
| 2230 | (tramp-flush-file-properties v2 v2-localname))) | ||
| 2231 | |||
| 2232 | ;; Handle `preserve-extended-attributes'. We ignore | ||
| 2233 | ;; possible errors, because ACL strings could be | ||
| 2234 | ;; incompatible. | ||
| 2235 | (when-let* ((attributes (and preserve-extended-attributes | ||
| 2236 | (file-extended-attributes filename)))) | ||
| 2237 | (ignore-errors | ||
| 2238 | (set-file-extended-attributes newname attributes))) | ||
| 2239 | |||
| 2240 | ;; KEEP-DATE handling. | ||
| 2241 | (when (and keep-date (not copy-keep-date)) | ||
| 2242 | (set-file-times | ||
| 2243 | newname file-times (unless ok-if-already-exists 'nofollow))) | ||
| 2244 | |||
| 2245 | ;; Set the mode. | ||
| 2246 | (unless (and keep-date copy-keep-date) | ||
| 2247 | (set-file-modes newname file-modes)))))))) | ||
| 2248 | 2254 | ||
| 2249 | (defun tramp-do-copy-or-rename-file-via-buffer | 2255 | (defun tramp-do-copy-or-rename-file-via-buffer |
| 2250 | (op filename newname _ok-if-already-exists _keep-date) | 2256 | (op filename newname _ok-if-already-exists _keep-date) |
| @@ -3119,7 +3125,7 @@ will be used." | |||
| 3119 | ;; character to read. When a process does | 3125 | ;; character to read. When a process does |
| 3120 | ;; not read from stdin, like magit, it | 3126 | ;; not read from stdin, like magit, it |
| 3121 | ;; should set a timeout | 3127 | ;; should set a timeout |
| 3122 | ;; instead. See`tramp-pipe-stty-settings'. | 3128 | ;; instead. See `tramp-pipe-stty-settings'. |
| 3123 | ;; (Bug#62093) | 3129 | ;; (Bug#62093) |
| 3124 | ;; FIXME: Shall we rather use "stty raw"? | 3130 | ;; FIXME: Shall we rather use "stty raw"? |
| 3125 | (tramp-send-command | 3131 | (tramp-send-command |
| @@ -5631,7 +5637,7 @@ Nonexistent directories are removed from spec." | |||
| 5631 | (lambda (x) (not (tramp-get-file-property vec x "file-directory-p"))) | 5637 | (lambda (x) (not (tramp-get-file-property vec x "file-directory-p"))) |
| 5632 | remote-path)))))) | 5638 | remote-path)))))) |
| 5633 | 5639 | ||
| 5634 | ;; The PIPE_BUF in POSIX [1] can be as low as 512 [2]. Here are the values | 5640 | ;; The PIPE_BUF in POSIX [1] can be as low as 512 [2]. Here are the values |
| 5635 | ;; on various platforms: | 5641 | ;; on various platforms: |
| 5636 | ;; - 512 on macOS, FreeBSD, NetBSD, OpenBSD, MirBSD, native Windows. | 5642 | ;; - 512 on macOS, FreeBSD, NetBSD, OpenBSD, MirBSD, native Windows. |
| 5637 | ;; - 4 KiB on Linux, OSF/1, Cygwin, Haiku. | 5643 | ;; - 4 KiB on Linux, OSF/1, Cygwin, Haiku. |
diff --git a/lisp/net/tramp-smb.el b/lisp/net/tramp-smb.el index 64bde348775..aeb7c01c03f 100644 --- a/lisp/net/tramp-smb.el +++ b/lisp/net/tramp-smb.el | |||
| @@ -114,6 +114,7 @@ this variable \"client min protocol=NT1\"." | |||
| 114 | "Read from server failed, maybe it closed the connection" | 114 | "Read from server failed, maybe it closed the connection" |
| 115 | "Call timed out: server did not respond" | 115 | "Call timed out: server did not respond" |
| 116 | (: (+ (not blank)) ": command not found") | 116 | (: (+ (not blank)) ": command not found") |
| 117 | (: (+ (not blank)) " does not exist") | ||
| 117 | "Server doesn't support UNIX CIFS calls" | 118 | "Server doesn't support UNIX CIFS calls" |
| 118 | (| ;; Samba. | 119 | (| ;; Samba. |
| 119 | "ERRDOS" | 120 | "ERRDOS" |
| @@ -596,66 +597,63 @@ KEEP-DATE has no effect in case NEWNAME resides on an SMB server. | |||
| 596 | PRESERVE-UID-GID and PRESERVE-EXTENDED-ATTRIBUTES are completely ignored." | 597 | PRESERVE-UID-GID and PRESERVE-EXTENDED-ATTRIBUTES are completely ignored." |
| 597 | (setq filename (expand-file-name filename) | 598 | (setq filename (expand-file-name filename) |
| 598 | newname (expand-file-name newname)) | 599 | newname (expand-file-name newname)) |
| 599 | (with-tramp-progress-reporter | ||
| 600 | (tramp-dissect-file-name | ||
| 601 | (if (tramp-tramp-file-p filename) filename newname)) | ||
| 602 | 0 (format "Copying %s to %s" filename newname) | ||
| 603 | 600 | ||
| 604 | (if (file-directory-p filename) | 601 | (with-parsed-tramp-file-name |
| 605 | (copy-directory filename newname keep-date 'parents 'copy-contents) | 602 | (if (tramp-tramp-file-p filename) filename newname) nil |
| 603 | (with-tramp-progress-reporter | ||
| 604 | v 0 (format "Copying %s to %s" filename newname) | ||
| 605 | |||
| 606 | (if (file-directory-p filename) | ||
| 607 | (copy-directory filename newname keep-date 'parents 'copy-contents) | ||
| 608 | |||
| 609 | (tramp-barf-if-file-missing v filename | ||
| 610 | ;; `file-local-copy' returns a file name also for a local | ||
| 611 | ;; file with `jka-compr-handler', so we cannot trust its | ||
| 612 | ;; result as indication for a remote file name. | ||
| 613 | (if-let* ((tmpfile | ||
| 614 | (and (tramp-tramp-file-p filename) | ||
| 615 | (file-local-copy filename)))) | ||
| 616 | ;; Remote filename. | ||
| 617 | (condition-case err | ||
| 618 | (rename-file tmpfile newname ok-if-already-exists) | ||
| 619 | ((error quit) | ||
| 620 | (delete-file tmpfile) | ||
| 621 | (signal (car err) (cdr err)))) | ||
| 622 | |||
| 623 | ;; Remote newname. | ||
| 624 | (when (and (file-directory-p newname) | ||
| 625 | (directory-name-p newname)) | ||
| 626 | (setq newname | ||
| 627 | (expand-file-name | ||
| 628 | (file-name-nondirectory filename) newname))) | ||
| 629 | |||
| 630 | (when (and (not ok-if-already-exists) (file-exists-p newname)) | ||
| 631 | (tramp-error v 'file-already-exists newname)) | ||
| 632 | (when (and (file-directory-p newname) | ||
| 633 | (not (directory-name-p newname))) | ||
| 634 | (tramp-error v 'file-error "File is a directory %s" newname)) | ||
| 635 | |||
| 636 | (unless (tramp-smb-get-share v) | ||
| 637 | (tramp-error | ||
| 638 | v 'file-error "Target `%s' must contain a share name" newname)) | ||
| 639 | (unless (tramp-smb-send-command | ||
| 640 | v (format "put %s %s" | ||
| 641 | (tramp-smb-shell-quote-argument filename) | ||
| 642 | (tramp-smb-shell-quote-localname v))) | ||
| 643 | (tramp-error | ||
| 644 | v 'file-error "Cannot copy `%s' to `%s'" filename newname)) | ||
| 606 | 645 | ||
| 607 | (unless (file-exists-p filename) | 646 | ;; When newname did exist, we have wrong cached values. |
| 608 | (tramp-error | 647 | (when (tramp-tramp-file-p newname) |
| 609 | (tramp-dissect-file-name | 648 | (with-parsed-tramp-file-name newname v2 |
| 610 | (if (tramp-tramp-file-p filename) filename newname)) | 649 | (tramp-flush-file-properties v2 v2-localname)))))) |
| 611 | 'file-missing filename)) | 650 | |
| 612 | 651 | ;; KEEP-DATE handling. | |
| 613 | ;; `file-local-copy' returns a file name also for a local file | 652 | (when keep-date |
| 614 | ;; with `jka-compr-handler', so we cannot trust its result as | 653 | (set-file-times |
| 615 | ;; indication for a remote file name. | 654 | newname |
| 616 | (if-let* ((tmpfile | 655 | (file-attribute-modification-time (file-attributes filename)) |
| 617 | (and (tramp-tramp-file-p filename) (file-local-copy filename)))) | 656 | (unless ok-if-already-exists 'nofollow)))))) |
| 618 | ;; Remote filename. | ||
| 619 | (condition-case err | ||
| 620 | (rename-file tmpfile newname ok-if-already-exists) | ||
| 621 | ((error quit) | ||
| 622 | (delete-file tmpfile) | ||
| 623 | (signal (car err) (cdr err)))) | ||
| 624 | |||
| 625 | ;; Remote newname. | ||
| 626 | (when (and (file-directory-p newname) | ||
| 627 | (directory-name-p newname)) | ||
| 628 | (setq newname | ||
| 629 | (expand-file-name (file-name-nondirectory filename) newname))) | ||
| 630 | |||
| 631 | (with-parsed-tramp-file-name newname nil | ||
| 632 | (when (and (not ok-if-already-exists) (file-exists-p newname)) | ||
| 633 | (tramp-error v 'file-already-exists newname)) | ||
| 634 | (when (and (file-directory-p newname) | ||
| 635 | (not (directory-name-p newname))) | ||
| 636 | (tramp-error v 'file-error "File is a directory %s" newname)) | ||
| 637 | |||
| 638 | (unless (tramp-smb-get-share v) | ||
| 639 | (tramp-error | ||
| 640 | v 'file-error "Target `%s' must contain a share name" newname)) | ||
| 641 | (unless (tramp-smb-send-command | ||
| 642 | v (format "put %s %s" | ||
| 643 | (tramp-smb-shell-quote-argument filename) | ||
| 644 | (tramp-smb-shell-quote-localname v))) | ||
| 645 | (tramp-error | ||
| 646 | v 'file-error "Cannot copy `%s' to `%s'" filename newname)) | ||
| 647 | |||
| 648 | ;; When newname did exist, we have wrong cached values. | ||
| 649 | (when (tramp-tramp-file-p newname) | ||
| 650 | (with-parsed-tramp-file-name newname v2 | ||
| 651 | (tramp-flush-file-properties v2 v2-localname)))))) | ||
| 652 | |||
| 653 | ;; KEEP-DATE handling. | ||
| 654 | (when keep-date | ||
| 655 | (set-file-times | ||
| 656 | newname | ||
| 657 | (file-attribute-modification-time (file-attributes filename)) | ||
| 658 | (unless ok-if-already-exists 'nofollow))))) | ||
| 659 | 657 | ||
| 660 | (defun tramp-smb-handle-delete-directory (directory &optional recursive trash) | 658 | (defun tramp-smb-handle-delete-directory (directory &optional recursive trash) |
| 661 | "Like `delete-directory' for Tramp files." | 659 | "Like `delete-directory' for Tramp files." |
| @@ -1306,46 +1304,45 @@ PRESERVE-UID-GID and PRESERVE-EXTENDED-ATTRIBUTES are completely ignored." | |||
| 1306 | 1304 | ||
| 1307 | (with-parsed-tramp-file-name | 1305 | (with-parsed-tramp-file-name |
| 1308 | (if (tramp-tramp-file-p filename) filename newname) nil | 1306 | (if (tramp-tramp-file-p filename) filename newname) nil |
| 1309 | (unless (file-exists-p filename) | 1307 | (tramp-barf-if-file-missing v filename |
| 1310 | (tramp-error v 'file-missing filename)) | 1308 | (when (and (not ok-if-already-exists) (file-exists-p newname)) |
| 1311 | (when (and (not ok-if-already-exists) (file-exists-p newname)) | 1309 | (tramp-error v 'file-already-exists newname)) |
| 1312 | (tramp-error v 'file-already-exists newname)) | 1310 | (when (and (file-directory-p newname) |
| 1313 | (when (and (file-directory-p newname) | 1311 | (not (directory-name-p newname))) |
| 1314 | (not (directory-name-p newname))) | 1312 | (tramp-error v 'file-error "File is a directory %s" newname)) |
| 1315 | (tramp-error v 'file-error "File is a directory %s" newname)) | ||
| 1316 | 1313 | ||
| 1317 | (with-tramp-progress-reporter | 1314 | (with-tramp-progress-reporter |
| 1318 | v 0 (format "Renaming %s to %s" filename newname) | 1315 | v 0 (format "Renaming %s to %s" filename newname) |
| 1319 | 1316 | ||
| 1320 | (if (and (not (file-exists-p newname)) | 1317 | (if (and (not (file-exists-p newname)) |
| 1321 | (tramp-equal-remote filename newname) | 1318 | (tramp-equal-remote filename newname) |
| 1322 | (string-equal | 1319 | (string-equal |
| 1323 | (tramp-smb-get-share (tramp-dissect-file-name filename)) | 1320 | (tramp-smb-get-share (tramp-dissect-file-name filename)) |
| 1324 | (tramp-smb-get-share (tramp-dissect-file-name newname)))) | 1321 | (tramp-smb-get-share (tramp-dissect-file-name newname)))) |
| 1325 | ;; We can rename directly. | 1322 | ;; We can rename directly. |
| 1326 | (with-parsed-tramp-file-name filename v1 | 1323 | (with-parsed-tramp-file-name filename v1 |
| 1327 | (with-parsed-tramp-file-name newname v2 | 1324 | (with-parsed-tramp-file-name newname v2 |
| 1328 | 1325 | ||
| 1329 | ;; We must also flush the cache of the directory, because | 1326 | ;; We must also flush the cache of the directory, because |
| 1330 | ;; `file-attributes' reads the values from there. | 1327 | ;; `file-attributes' reads the values from there. |
| 1331 | (tramp-flush-file-properties v1 v1-localname) | 1328 | (tramp-flush-file-properties v1 v1-localname) |
| 1332 | (tramp-flush-file-properties v2 v2-localname) | 1329 | (tramp-flush-file-properties v2 v2-localname) |
| 1333 | (unless (tramp-smb-get-share v2) | 1330 | (unless (tramp-smb-get-share v2) |
| 1334 | (tramp-error | 1331 | (tramp-error |
| 1335 | v2 'file-error | 1332 | v2 'file-error |
| 1336 | "Target `%s' must contain a share name" newname)) | 1333 | "Target `%s' must contain a share name" newname)) |
| 1337 | (unless (tramp-smb-send-command | 1334 | (unless (tramp-smb-send-command |
| 1338 | v2 (format "rename %s %s" | 1335 | v2 (format "rename %s %s" |
| 1339 | (tramp-smb-shell-quote-localname v1) | 1336 | (tramp-smb-shell-quote-localname v1) |
| 1340 | (tramp-smb-shell-quote-localname v2))) | 1337 | (tramp-smb-shell-quote-localname v2))) |
| 1341 | (tramp-error v2 'file-error "Cannot rename `%s'" filename)))) | 1338 | (tramp-error v2 'file-error "Cannot rename `%s'" filename)))) |
| 1342 | 1339 | ||
| 1343 | ;; We must rename via copy. | 1340 | ;; We must rename via copy. |
| 1344 | (copy-file | 1341 | (copy-file |
| 1345 | filename newname ok-if-already-exists 'keep-time 'preserve-uid-gid) | 1342 | filename newname ok-if-already-exists 'keep-time 'preserve-uid-gid) |
| 1346 | (if (file-directory-p filename) | 1343 | (if (file-directory-p filename) |
| 1347 | (delete-directory filename 'recursive) | 1344 | (delete-directory filename 'recursive) |
| 1348 | (delete-file filename)))))) | 1345 | (delete-file filename))))))) |
| 1349 | 1346 | ||
| 1350 | (defun tramp-smb-action-set-acl (proc vec) | 1347 | (defun tramp-smb-action-set-acl (proc vec) |
| 1351 | "Set ACL data." | 1348 | "Set ACL data." |
diff --git a/lisp/net/tramp-sudoedit.el b/lisp/net/tramp-sudoedit.el index 0202f933b74..517bd85736a 100644 --- a/lisp/net/tramp-sudoedit.el +++ b/lisp/net/tramp-sudoedit.el | |||
| @@ -244,84 +244,88 @@ absolute file names." | |||
| 244 | (unless (memq op '(copy rename)) | 244 | (unless (memq op '(copy rename)) |
| 245 | (error "Unknown operation `%s', must be `copy' or `rename'" op)) | 245 | (error "Unknown operation `%s', must be `copy' or `rename'" op)) |
| 246 | 246 | ||
| 247 | (setq filename (file-truename filename)) | ||
| 248 | (if (file-directory-p filename) | 247 | (if (file-directory-p filename) |
| 249 | (progn | 248 | (progn |
| 250 | (copy-directory filename newname keep-date t) | 249 | (copy-directory filename newname keep-date t) |
| 251 | (when (eq op 'rename) (delete-directory filename 'recursive))) | 250 | (when (eq op 'rename) (delete-directory filename 'recursive))) |
| 252 | 251 | (if (file-symlink-p filename) | |
| 253 | ;; FIXME: This should be optimized. Computing `file-attributes' | 252 | (progn |
| 254 | ;; checks already, whether the file exists. | 253 | (make-symbolic-link |
| 255 | (let ((t1 (tramp-sudoedit-file-name-p filename)) | 254 | (file-symlink-p filename) newname ok-if-already-exists) |
| 256 | (t2 (tramp-sudoedit-file-name-p newname)) | 255 | (when (eq op 'rename) (delete-file filename))) |
| 257 | (file-times (file-attribute-modification-time | 256 | |
| 258 | (file-attributes filename))) | 257 | ;; FIXME: This should be optimized. Computing `file-attributes' |
| 259 | (file-modes (tramp-default-file-modes filename)) | 258 | ;; checks already, whether the file exists. |
| 260 | (attributes (and preserve-extended-attributes | 259 | (let ((t1 (tramp-sudoedit-file-name-p filename)) |
| 261 | (file-extended-attributes filename))) | 260 | (t2 (tramp-sudoedit-file-name-p newname)) |
| 262 | (sudoedit-operation | 261 | (file-times (file-attribute-modification-time |
| 263 | (cond | 262 | (file-attributes filename))) |
| 264 | ((and (eq op 'copy) preserve-uid-gid) '("cp" "-f" "-p")) | 263 | (file-modes (tramp-default-file-modes filename)) |
| 265 | ((eq op 'copy) '("cp" "-f")) | 264 | (attributes (and preserve-extended-attributes |
| 266 | ((eq op 'rename) '("mv" "-f")))) | 265 | (file-extended-attributes filename))) |
| 267 | (msg-operation (if (eq op 'copy) "Copying" "Renaming"))) | 266 | (sudoedit-operation |
| 268 | 267 | (cond | |
| 269 | (with-parsed-tramp-file-name (if t1 filename newname) nil | 268 | ((and (eq op 'copy) preserve-uid-gid) '("cp" "-f" "-p")) |
| 270 | (tramp-barf-if-file-missing v filename | 269 | ((eq op 'copy) '("cp" "-f")) |
| 271 | (when (and (not ok-if-already-exists) (file-exists-p newname)) | 270 | ((eq op 'rename) '("mv" "-f")))) |
| 272 | (tramp-error v 'file-already-exists newname)) | 271 | (msg-operation (if (eq op 'copy) "Copying" "Renaming"))) |
| 273 | (when (and (file-directory-p newname) | 272 | |
| 274 | (not (directory-name-p newname))) | 273 | (with-parsed-tramp-file-name (if t1 filename newname) nil |
| 275 | (tramp-error v 'file-error "File is a directory %s" newname)) | 274 | (tramp-barf-if-file-missing v filename |
| 276 | 275 | (when (and (not ok-if-already-exists) (file-exists-p newname)) | |
| 277 | (if (or (and (tramp-tramp-file-p filename) (not t1)) | 276 | (tramp-error v 'file-already-exists newname)) |
| 278 | (and (tramp-tramp-file-p newname) (not t2))) | 277 | (when (and (file-directory-p newname) |
| 279 | ;; We cannot copy or rename directly. | 278 | (not (directory-name-p newname))) |
| 280 | (let ((tmpfile (tramp-compat-make-temp-file filename))) | 279 | (tramp-error v 'file-error "File is a directory %s" newname)) |
| 281 | (if (eq op 'copy) | 280 | |
| 282 | (copy-file filename tmpfile t) | 281 | (if (or (and (tramp-tramp-file-p filename) (not t1)) |
| 283 | (rename-file filename tmpfile t)) | 282 | (and (tramp-tramp-file-p newname) (not t2))) |
| 284 | (rename-file tmpfile newname ok-if-already-exists)) | 283 | ;; We cannot copy or rename directly. |
| 285 | 284 | (let ((tmpfile (tramp-compat-make-temp-file filename))) | |
| 286 | ;; Direct action. | 285 | (if (eq op 'copy) |
| 287 | (with-tramp-progress-reporter | 286 | (copy-file filename tmpfile t) |
| 288 | v 0 (format "%s %s to %s" msg-operation filename newname) | 287 | (rename-file filename tmpfile t)) |
| 289 | (unless (tramp-sudoedit-send-command | 288 | (rename-file tmpfile newname ok-if-already-exists)) |
| 290 | v sudoedit-operation | 289 | |
| 291 | (tramp-unquote-file-local-name filename) | 290 | ;; Direct action. |
| 292 | (tramp-unquote-file-local-name newname)) | 291 | (with-tramp-progress-reporter |
| 293 | (tramp-error | 292 | v 0 (format "%s %s to %s" msg-operation filename newname) |
| 294 | v 'file-error | 293 | (unless (tramp-sudoedit-send-command |
| 295 | "Error %s `%s' `%s'" msg-operation filename newname)))) | 294 | v sudoedit-operation |
| 296 | 295 | (tramp-unquote-file-local-name filename) | |
| 297 | ;; When `newname' is local, we must change the ownership to | 296 | (tramp-unquote-file-local-name newname)) |
| 298 | ;; the local user. | 297 | (tramp-error |
| 299 | (unless (tramp-tramp-file-p newname) | 298 | v 'file-error |
| 300 | (tramp-set-file-uid-gid | 299 | "Error %s `%s' `%s'" msg-operation filename newname)))) |
| 301 | (concat (file-remote-p filename) newname) | 300 | |
| 302 | (tramp-get-local-uid 'integer) | 301 | ;; When `newname' is local, we must change the ownership |
| 303 | (tramp-get-local-gid 'integer))) | 302 | ;; to the local user. |
| 304 | 303 | (unless (tramp-tramp-file-p newname) | |
| 305 | ;; Set the time and mode. Mask possible errors. | 304 | (tramp-set-file-uid-gid |
| 306 | (when keep-date | 305 | (concat (file-remote-p filename) newname) |
| 307 | (ignore-errors | 306 | (tramp-get-local-uid 'integer) |
| 308 | (set-file-times | 307 | (tramp-get-local-gid 'integer))) |
| 309 | newname file-times (unless ok-if-already-exists 'nofollow)) | 308 | |
| 310 | (set-file-modes newname file-modes))) | 309 | ;; Set the time and mode. Mask possible errors. |
| 311 | 310 | (when keep-date | |
| 312 | ;; Handle `preserve-extended-attributes'. We ignore possible | 311 | (ignore-errors |
| 313 | ;; errors, because ACL strings could be incompatible. | 312 | (set-file-times |
| 314 | (when attributes | 313 | newname file-times (unless ok-if-already-exists 'nofollow)) |
| 315 | (ignore-errors | 314 | (set-file-modes newname file-modes))) |
| 316 | (set-file-extended-attributes newname attributes))) | 315 | |
| 317 | 316 | ;; Handle `preserve-extended-attributes'. We ignore possible | |
| 318 | (when (and t1 (eq op 'rename)) | 317 | ;; errors, because ACL strings could be incompatible. |
| 319 | (with-parsed-tramp-file-name filename v1 | 318 | (when attributes |
| 320 | (tramp-flush-file-properties v1 v1-localname))) | 319 | (ignore-errors |
| 321 | 320 | (set-file-extended-attributes newname attributes))) | |
| 322 | (when t2 | 321 | |
| 323 | (with-parsed-tramp-file-name newname v2 | 322 | (when (and t1 (eq op 'rename)) |
| 324 | (tramp-flush-file-properties v2 v2-localname)))))))) | 323 | (with-parsed-tramp-file-name filename v1 |
| 324 | (tramp-flush-file-properties v1 v1-localname))) | ||
| 325 | |||
| 326 | (when t2 | ||
| 327 | (with-parsed-tramp-file-name newname v2 | ||
| 328 | (tramp-flush-file-properties v2 v2-localname))))))))) | ||
| 325 | 329 | ||
| 326 | (defun tramp-sudoedit-handle-copy-file | 330 | (defun tramp-sudoedit-handle-copy-file |
| 327 | (filename newname &optional ok-if-already-exists keep-date | 331 | (filename newname &optional ok-if-already-exists keep-date |
diff --git a/lisp/net/tramp.el b/lisp/net/tramp.el index 190e1871234..6f2d891db5d 100644 --- a/lisp/net/tramp.el +++ b/lisp/net/tramp.el | |||
| @@ -2107,7 +2107,7 @@ does not exist, otherwise propagate the error." | |||
| 2107 | `(condition-case ,err | 2107 | `(condition-case ,err |
| 2108 | (progn ,@body) | 2108 | (progn ,@body) |
| 2109 | (error | 2109 | (error |
| 2110 | (if (not (file-exists-p ,filename)) | 2110 | (if (not (or (file-exists-p ,filename) (file-symlink-p ,filename))) |
| 2111 | (tramp-error ,vec 'file-missing ,filename) | 2111 | (tramp-error ,vec 'file-missing ,filename) |
| 2112 | (signal (car ,err) (cdr ,err))))))) | 2112 | (signal (car ,err) (cdr ,err))))))) |
| 2113 | 2113 | ||
| @@ -3576,12 +3576,17 @@ BODY is the backend specific code." | |||
| 3576 | (when (tramp-connectable-p ,filename) | 3576 | (when (tramp-connectable-p ,filename) |
| 3577 | (with-parsed-tramp-file-name (expand-file-name ,filename) nil | 3577 | (with-parsed-tramp-file-name (expand-file-name ,filename) nil |
| 3578 | (with-tramp-file-property v localname "file-exists-p" | 3578 | (with-tramp-file-property v localname "file-exists-p" |
| 3579 | ;; Examine `file-attributes' cache to see if request can | 3579 | (cond |
| 3580 | ;; be satisfied without remote operation. | 3580 | ;; Examine `file-attributes' cache to see if request can |
| 3581 | (if (tramp-file-property-p v localname "file-attributes") | 3581 | ;; be satisfied without remote operation. |
| 3582 | (not | 3582 | ((and-let* |
| 3583 | (null (tramp-get-file-property v localname "file-attributes"))) | 3583 | (((tramp-file-property-p v localname "file-attributes")) |
| 3584 | ,@body)))))) | 3584 | (fa (tramp-get-file-property v localname "file-attributes")) |
| 3585 | ((not (stringp (car fa))))))) | ||
| 3586 | ;; Symlink to a non-existing target counts as nil. | ||
| 3587 | ((file-symlink-p ,filename) | ||
| 3588 | (file-exists-p (file-truename ,filename))) | ||
| 3589 | (t ,@body))))))) | ||
| 3585 | 3590 | ||
| 3586 | (defmacro tramp-skeleton-file-local-copy (filename &rest body) | 3591 | (defmacro tramp-skeleton-file-local-copy (filename &rest body) |
| 3587 | "Skeleton for `tramp-*-handle-file-local-copy'. | 3592 | "Skeleton for `tramp-*-handle-file-local-copy'. |
| @@ -3846,7 +3851,7 @@ BODY is the backend specific code." | |||
| 3846 | ;; We cannot add "file-attributes", "file-executable-p", | 3851 | ;; We cannot add "file-attributes", "file-executable-p", |
| 3847 | ;; "file-ownership-preserved-p", "file-readable-p", | 3852 | ;; "file-ownership-preserved-p", "file-readable-p", |
| 3848 | ;; "file-writable-p". | 3853 | ;; "file-writable-p". |
| 3849 | '("file-directory-p" "file-exists-p" "file-symlinkp" "file-truename") | 3854 | '("file-directory-p" "file-exists-p" "file-symlink-p" "file-truename") |
| 3850 | (tramp-flush-file-properties v localname)) | 3855 | (tramp-flush-file-properties v localname)) |
| 3851 | (condition-case err | 3856 | (condition-case err |
| 3852 | (progn ,@body) | 3857 | (progn ,@body) |
diff --git a/test/lisp/net/tramp-tests.el b/test/lisp/net/tramp-tests.el index 1efafb68fbc..ccb3731fc09 100644 --- a/test/lisp/net/tramp-tests.el +++ b/test/lisp/net/tramp-tests.el | |||
| @@ -153,7 +153,7 @@ | |||
| 153 | tramp-error-show-message-timeout nil | 153 | tramp-error-show-message-timeout nil |
| 154 | tramp-persistency-file-name nil | 154 | tramp-persistency-file-name nil |
| 155 | tramp-verbose 0 | 155 | tramp-verbose 0 |
| 156 | vc-handled-backends nil) | 156 | vc-handled-backends (unless noninteractive vc-handled-backends)) |
| 157 | 157 | ||
| 158 | (defconst tramp-test-name-prefix "tramp-test" | 158 | (defconst tramp-test-name-prefix "tramp-test" |
| 159 | "Prefix to use for temporary test files.") | 159 | "Prefix to use for temporary test files.") |
| @@ -2871,7 +2871,9 @@ This checks also `file-name-as-directory', `file-name-directory', | |||
| 2871 | (dolist (quoted (if (tramp--test-expensive-test-p) '(nil t) '(nil))) | 2871 | (dolist (quoted (if (tramp--test-expensive-test-p) '(nil t) '(nil))) |
| 2872 | (let ((tmp-name1 (tramp--test-make-temp-name nil quoted)) | 2872 | (let ((tmp-name1 (tramp--test-make-temp-name nil quoted)) |
| 2873 | (tmp-name2 (tramp--test-make-temp-name nil quoted)) | 2873 | (tmp-name2 (tramp--test-make-temp-name nil quoted)) |
| 2874 | (tmp-name3 (tramp--test-make-temp-name 'local quoted))) | 2874 | (tmp-name3 (tramp--test-make-temp-name 'local quoted)) |
| 2875 | (tmp-name4 | ||
| 2876 | (file-name-nondirectory (tramp--test-make-temp-name 'local quoted)))) | ||
| 2875 | (dolist (source-target | 2877 | (dolist (source-target |
| 2876 | `(;; Copy on remote side. | 2878 | `(;; Copy on remote side. |
| 2877 | (,tmp-name1 . ,tmp-name2) | 2879 | (,tmp-name1 . ,tmp-name2) |
| @@ -2879,8 +2881,12 @@ This checks also `file-name-as-directory', `file-name-directory', | |||
| 2879 | (,tmp-name1 . ,tmp-name3) | 2881 | (,tmp-name1 . ,tmp-name3) |
| 2880 | ;; Copy from local side to remote side. | 2882 | ;; Copy from local side to remote side. |
| 2881 | (,tmp-name3 . ,tmp-name1))) | 2883 | (,tmp-name3 . ,tmp-name1))) |
| 2882 | (let ((source (car source-target)) | 2884 | (let* ((source (car source-target)) |
| 2883 | (target (cdr source-target))) | 2885 | (source-link |
| 2886 | (expand-file-name tmp-name4 (file-name-directory source))) | ||
| 2887 | (target (cdr source-target)) | ||
| 2888 | (target-link | ||
| 2889 | (expand-file-name tmp-name4 (file-name-directory target)))) | ||
| 2884 | 2890 | ||
| 2885 | ;; Copy simple file. | 2891 | ;; Copy simple file. |
| 2886 | (unwind-protect | 2892 | (unwind-protect |
| @@ -2905,6 +2911,26 @@ This checks also `file-name-as-directory', `file-name-directory', | |||
| 2905 | (ignore-errors (delete-file source)) | 2911 | (ignore-errors (delete-file source)) |
| 2906 | (ignore-errors (delete-file target))) | 2912 | (ignore-errors (delete-file target))) |
| 2907 | 2913 | ||
| 2914 | ;; Copy symlinked file. | ||
| 2915 | (unwind-protect | ||
| 2916 | (tramp--test-ignore-make-symbolic-link-error | ||
| 2917 | (write-region "foo" nil source-link) | ||
| 2918 | (should (file-exists-p source-link)) | ||
| 2919 | (make-symbolic-link tmp-name4 source) | ||
| 2920 | (should (file-exists-p source)) | ||
| 2921 | (should (string-equal (file-symlink-p source) tmp-name4)) | ||
| 2922 | (copy-file source target) | ||
| 2923 | ;; Some backends like tramp-gvfs.el do not create the | ||
| 2924 | ;; link on the target. | ||
| 2925 | (when (file-symlink-p target) | ||
| 2926 | (should (string-equal (file-symlink-p target) tmp-name4)))) | ||
| 2927 | |||
| 2928 | ;; Cleanup. | ||
| 2929 | (ignore-errors (delete-file source)) | ||
| 2930 | (ignore-errors (delete-file source-link)) | ||
| 2931 | (ignore-errors (delete-file target)) | ||
| 2932 | (ignore-errors (delete-file target-link))) | ||
| 2933 | |||
| 2908 | ;; Copy file to directory. | 2934 | ;; Copy file to directory. |
| 2909 | (unwind-protect | 2935 | (unwind-protect |
| 2910 | ;; This doesn't work on FTP. | 2936 | ;; This doesn't work on FTP. |
| @@ -2980,7 +3006,9 @@ This checks also `file-name-as-directory', `file-name-directory', | |||
| 2980 | (dolist (quoted (if (tramp--test-expensive-test-p) '(nil t) '(nil))) | 3006 | (dolist (quoted (if (tramp--test-expensive-test-p) '(nil t) '(nil))) |
| 2981 | (let ((tmp-name1 (tramp--test-make-temp-name nil quoted)) | 3007 | (let ((tmp-name1 (tramp--test-make-temp-name nil quoted)) |
| 2982 | (tmp-name2 (tramp--test-make-temp-name nil quoted)) | 3008 | (tmp-name2 (tramp--test-make-temp-name nil quoted)) |
| 2983 | (tmp-name3 (tramp--test-make-temp-name 'local quoted))) | 3009 | (tmp-name3 (tramp--test-make-temp-name 'local quoted)) |
| 3010 | (tmp-name4 | ||
| 3011 | (file-name-nondirectory (tramp--test-make-temp-name 'local quoted)))) | ||
| 2984 | (dolist (source-target | 3012 | (dolist (source-target |
| 2985 | `(;; Rename on remote side. | 3013 | `(;; Rename on remote side. |
| 2986 | (,tmp-name1 . ,tmp-name2) | 3014 | (,tmp-name1 . ,tmp-name2) |
| @@ -2988,8 +3016,12 @@ This checks also `file-name-as-directory', `file-name-directory', | |||
| 2988 | (,tmp-name1 . ,tmp-name3) | 3016 | (,tmp-name1 . ,tmp-name3) |
| 2989 | ;; Rename from local side to remote side. | 3017 | ;; Rename from local side to remote side. |
| 2990 | (,tmp-name3 . ,tmp-name1))) | 3018 | (,tmp-name3 . ,tmp-name1))) |
| 2991 | (let ((source (car source-target)) | 3019 | (let* ((source (car source-target)) |
| 2992 | (target (cdr source-target))) | 3020 | (source-link |
| 3021 | (expand-file-name tmp-name4 (file-name-directory source))) | ||
| 3022 | (target (cdr source-target)) | ||
| 3023 | (target-link | ||
| 3024 | (expand-file-name tmp-name4 (file-name-directory target)))) | ||
| 2993 | 3025 | ||
| 2994 | ;; Rename simple file. | 3026 | ;; Rename simple file. |
| 2995 | (unwind-protect | 3027 | (unwind-protect |
| @@ -3018,6 +3050,27 @@ This checks also `file-name-as-directory', `file-name-directory', | |||
| 3018 | (ignore-errors (delete-file source)) | 3050 | (ignore-errors (delete-file source)) |
| 3019 | (ignore-errors (delete-file target))) | 3051 | (ignore-errors (delete-file target))) |
| 3020 | 3052 | ||
| 3053 | ;; Rename symlinked file. | ||
| 3054 | (unwind-protect | ||
| 3055 | (tramp--test-ignore-make-symbolic-link-error | ||
| 3056 | (write-region "foo" nil source-link) | ||
| 3057 | (should (file-exists-p source-link)) | ||
| 3058 | (make-symbolic-link tmp-name4 source) | ||
| 3059 | (should (file-exists-p source)) | ||
| 3060 | (should (string-equal (file-symlink-p source) tmp-name4)) | ||
| 3061 | (rename-file source target) | ||
| 3062 | (should-not (file-exists-p source)) | ||
| 3063 | ;; Some backends like tramp-gvfs.el do not create the | ||
| 3064 | ;; link on the target. | ||
| 3065 | (when (file-symlink-p target) | ||
| 3066 | (should (string-equal (file-symlink-p target) tmp-name4)))) | ||
| 3067 | |||
| 3068 | ;; Cleanup. | ||
| 3069 | (ignore-errors (delete-file source)) | ||
| 3070 | (ignore-errors (delete-file source-link)) | ||
| 3071 | (ignore-errors (delete-file target)) | ||
| 3072 | (ignore-errors (delete-file target-link))) | ||
| 3073 | |||
| 3021 | ;; Rename file to directory. | 3074 | ;; Rename file to directory. |
| 3022 | (unwind-protect | 3075 | (unwind-protect |
| 3023 | (progn | 3076 | (progn |
| @@ -3814,6 +3867,18 @@ This tests also `access-file', `file-readable-p', | |||
| 3814 | (if quoted #'file-name-quote #'identity) | 3867 | (if quoted #'file-name-quote #'identity) |
| 3815 | (file-attribute-type attr)) | 3868 | (file-attribute-type attr)) |
| 3816 | (file-remote-p (file-truename tmp-name1) 'localname))) | 3869 | (file-remote-p (file-truename tmp-name1) 'localname))) |
| 3870 | (delete-file tmp-name2) | ||
| 3871 | |||
| 3872 | ;; A non-existent link target makes the file unaccessible. | ||
| 3873 | (make-symbolic-link "error" tmp-name2) | ||
| 3874 | (should (file-symlink-p tmp-name2)) | ||
| 3875 | (should-error | ||
| 3876 | (access-file tmp-name2 "error") | ||
| 3877 | :type 'file-missing) | ||
| 3878 | ;; `file-ownership-preserved-p' should return t for | ||
| 3879 | ;; symlinked files to a non-existing target. | ||
| 3880 | (when test-file-ownership-preserved-p | ||
| 3881 | (should (file-ownership-preserved-p tmp-name2 'group))) | ||
| 3817 | (delete-file tmp-name2)) | 3882 | (delete-file tmp-name2)) |
| 3818 | 3883 | ||
| 3819 | ;; Check, that "//" in symlinks are handled properly. | 3884 | ;; Check, that "//" in symlinks are handled properly. |
| @@ -4463,13 +4528,11 @@ This tests also `make-symbolic-link', `file-truename' and `add-name-to-file'." | |||
| 4463 | (make-symbolic-link tmp-name1 tmp-name2) | 4528 | (make-symbolic-link tmp-name1 tmp-name2) |
| 4464 | (should (file-symlink-p tmp-name1)) | 4529 | (should (file-symlink-p tmp-name1)) |
| 4465 | (should (file-symlink-p tmp-name2)) | 4530 | (should (file-symlink-p tmp-name2)) |
| 4466 | (should-not (file-regular-p tmp-name1)) | ||
| 4467 | (should-not (file-regular-p tmp-name2)) | ||
| 4468 | (should-error | 4531 | (should-error |
| 4469 | (file-truename tmp-name1) | 4532 | (file-regular-p tmp-name1) |
| 4470 | :type 'file-error) | 4533 | :type 'file-error) |
| 4471 | (should-error | 4534 | (should-error |
| 4472 | (file-truename tmp-name2) | 4535 | (file-regular-p tmp-name2) |
| 4473 | :type 'file-error)))) | 4536 | :type 'file-error)))) |
| 4474 | 4537 | ||
| 4475 | ;; Cleanup. | 4538 | ;; Cleanup. |
| @@ -7390,10 +7453,6 @@ This requires restrictions of file name syntax." | |||
| 7390 | (if quoted #'file-name-quote #'identity) | 7453 | (if quoted #'file-name-quote #'identity) |
| 7391 | (file-attribute-type (file-attributes file3))) | 7454 | (file-attribute-type (file-attributes file3))) |
| 7392 | (file-remote-p (file-truename file1) 'localname))) | 7455 | (file-remote-p (file-truename file1) 'localname))) |
| 7393 | ;; Check file contents. | ||
| 7394 | (with-temp-buffer | ||
| 7395 | (insert-file-contents file3) | ||
| 7396 | (should (string-equal (buffer-string) elt))) | ||
| 7397 | (delete-file file3)))) | 7456 | (delete-file file3)))) |
| 7398 | 7457 | ||
| 7399 | ;; Check file names. | 7458 | ;; Check file names. |