summaryrefslogtreecommitdiff
path: root/lisp/net
diff options
context:
space:
mode:
authorMichael Albinus <michael.albinus@gmx.de>2020-02-25 13:25:57 +0100
committerMichael Albinus <michael.albinus@gmx.de>2020-02-25 13:25:57 +0100
commit64af3c94a6197cd0c6a283880c900eeb5bf12961 (patch)
treede19019883ef7c94e21ec26615ee226a8d0cd67a /lisp/net
parent22524a6e39582d44c1365bad9a589618c2b0df27 (diff)
downloademacs-64af3c94a6197cd0c6a283880c900eeb5bf12961.tar.gz
emacs-64af3c94a6197cd0c6a283880c900eeb5bf12961.tar.bz2
emacs-64af3c94a6197cd0c6a283880c900eeb5bf12961.zip
Finish implementation of {set-}file-modes FLAG arg in Tramp
* lisp/net/tramp-adb.el (tramp-adb-handle-file-local-copy): Do not use 'nofollow for temporary files. Use `tramp-compat-set-file-modes'. (tramp-adb-handle-write-region): Do not use 'nofollow for temporary files. (tramp-adb-handle-set-file-modes): Implement FLAG. * lisp/net/tramp-compat.el (tramp-compat-file-modes) (tramp-compat-set-file-modes): New defaliases. * lisp/net/tramp-gvfs.el (tramp-gvfs-handle-set-file-modes): Make explicit check (eq flag 'nofollow). * lisp/net/tramp-sh.el (tramp-sh-handle-set-file-modes): Implement FLAG. (tramp-do-copy-or-rename-file-directly) (tramp-sh-handle-file-local-copy, tramp-sh-handle-write-region): Do not use 'nofollow for temporary files. (tramp-get-remote-chmod-h): New defun. * lisp/net/tramp-smb.el (tramp-smb-handle-set-file-modes): Implement FLAG. * lisp/net/tramp-sudoedit.el (tramp-sudoedit-handle-set-file-modes): Implement FLAG. (tramp-sudoedit-handle-write-region): Use `tramp-compat-set-file-modes'. * lisp/net/tramp.el (tramp-default-file-modes): Optional argument FLAG. (tramp-handle-file-modes): Use `file-truename' instead of `file-chase-links'. The latter function does not work for remote file names. (tramp-handle-write-region): Call `tramp-default-file-modes' with 'nofollow if needed. Do not use 'nofollow for temporary files. * test/lisp/net/tramp-tests.el (tramp--test-ignore-make-symbolic-link-error): Check also for "Cannot chmod .* with nofollow flag" error. (tramp-test20-file-modes): Extend test. (tramp--test-emacs28-p): New defun.
Diffstat (limited to 'lisp/net')
-rw-r--r--lisp/net/tramp-adb.el11
-rw-r--r--lisp/net/tramp-compat.el22
-rw-r--r--lisp/net/tramp-gvfs.el2
-rw-r--r--lisp/net/tramp-sh.el44
-rw-r--r--lisp/net/tramp-smb.el3
-rw-r--r--lisp/net/tramp-sudoedit.el21
-rw-r--r--lisp/net/tramp.el27
7 files changed, 86 insertions, 44 deletions
diff --git a/lisp/net/tramp-adb.el b/lisp/net/tramp-adb.el
index 96ef95dbe30..a118e7d2143 100644
--- a/lisp/net/tramp-adb.el
+++ b/lisp/net/tramp-adb.el
@@ -591,8 +591,9 @@ Emacs dired can't find files."
(ignore-errors (delete-file tmpfile))
(tramp-error
v 'file-error "Cannot make local copy of file `%s'" filename))
- (set-file-modes tmpfile (logior (or (file-modes filename) 0) #o0400)
- 'nofollow))
+ (set-file-modes
+ tmpfile
+ (logior (or (tramp-compat-file-modes filename 'nofollow) 0) #o0400)))
tmpfile)))
(defun tramp-adb-handle-file-writable-p (filename)
@@ -637,8 +638,7 @@ But handle the case, if the \"test\" command is not available."
(tmpfile (tramp-compat-make-temp-file filename)))
(when (and append (file-exists-p filename))
(copy-file filename tmpfile 'ok)
- (set-file-modes tmpfile (logior (or (file-modes tmpfile) 0) #o0600)
- 'nofollow))
+ (set-file-modes tmpfile (logior (or (file-modes tmpfile) 0) #o0600)))
(tramp-run-real-handler
#'write-region (list start end tmpfile append 'no-message lockname))
(with-tramp-progress-reporter
@@ -669,8 +669,9 @@ But handle the case, if the \"test\" command is not available."
(defun tramp-adb-handle-set-file-modes (filename mode &optional flag)
"Like `set-file-modes' for Tramp files."
- flag ;; FIXME: Support 'nofollow'.
(with-parsed-tramp-file-name filename nil
+ (when (and (eq flag 'nofollow) (file-symlink-p filename))
+ (tramp-error v 'file-error "Cannot chmod %s with %s flag" filename flag))
(tramp-flush-file-properties v localname)
(tramp-adb-send-command-and-check v (format "chmod %o %s" mode localname))))
diff --git a/lisp/net/tramp-compat.el b/lisp/net/tramp-compat.el
index 87bcd08b85a..8f85550bca0 100644
--- a/lisp/net/tramp-compat.el
+++ b/lisp/net/tramp-compat.el
@@ -165,7 +165,7 @@ This is a string of ten letters or dashes as in ls -l."
"The error symbol for the `file-missing' error.")
;; `file-local-name', `file-name-quoted-p', `file-name-quote' and
-;; `file-name-unquote' are introduced in Emacs 26.
+;; `file-name-unquote' are introduced in Emacs 26.1.
(defalias 'tramp-compat-file-local-name
(if (fboundp 'file-local-name)
#'file-local-name
@@ -175,7 +175,8 @@ It returns a file name which can be used directly as argument of
`process-file', `start-file-process', or `shell-command'."
(or (file-remote-p name 'localname) name))))
-;; `file-name-quoted-p' got a second argument in Emacs 27.1.
+;; `file-name-quoted-p', `file-name-quote' and `file-name-unquote' got
+;; a second argument in Emacs 27.1.
(defalias 'tramp-compat-file-name-quoted-p
(if (and
(fboundp 'file-name-quoted-p)
@@ -217,7 +218,7 @@ NAME is unquoted."
localname (if (= (length localname) 2) "/" (substring localname 2))))
(concat (file-remote-p name) localname)))))
-;; `tramp-syntax' has changed its meaning in Emacs 26. We still
+;; `tramp-syntax' has changed its meaning in Emacs 26.1. We still
;; support old settings.
(defsubst tramp-compat-tramp-syntax ()
"Return proper value of `tramp-syntax'."
@@ -275,6 +276,19 @@ A nil value for either argument stands for the current time."
(lambda (reporter &optional value _suffix)
(progress-reporter-update reporter value))))
+;; `file-modes' and `set-file-modes' got argument FLAG in Emacs 28.1.
+(defalias 'tramp-compat-file-modes
+ (if (equal (tramp-compat-funcall 'func-arity #'file-modes) '(1 . 2))
+ #'file-modes
+ (lambda (filename &optional _flag)
+ (file-modes filename))))
+
+(defalias 'tramp-compat-set-file-modes
+ (if (equal (tramp-compat-funcall 'func-arity #'set-file-modes) '(2 . 3))
+ #'set-file-modes
+ (lambda (filename mode &optional _flag)
+ (set-file-modes filename mode))))
+
(add-hook 'tramp-unload-hook
(lambda ()
(unload-feature 'tramp-loaddefs 'force)
@@ -284,6 +298,8 @@ A nil value for either argument stands for the current time."
;;; TODO:
;;
+;; * `func-arity' exists since Emacs 26.1.
+;;
;; * Starting with Emacs 27.1, there's no need to escape open
;; parentheses with a backslash in docstrings anymore.
diff --git a/lisp/net/tramp-gvfs.el b/lisp/net/tramp-gvfs.el
index 79835804bc0..3ce7bbbd4a3 100644
--- a/lisp/net/tramp-gvfs.el
+++ b/lisp/net/tramp-gvfs.el
@@ -1567,7 +1567,7 @@ If FILE-SYSTEM is non-nil, return file system attributes."
(with-parsed-tramp-file-name filename nil
(tramp-flush-file-properties v localname)
(tramp-gvfs-send-command
- v "gvfs-set-attribute" (if flag "-nt" "-t") "uint32"
+ v "gvfs-set-attribute" (if (eq flag 'nofollow) "-nt" "-t") "uint32"
(tramp-gvfs-url-file-name (tramp-make-tramp-file-name v))
"unix::mode" (number-to-string mode))))
diff --git a/lisp/net/tramp-sh.el b/lisp/net/tramp-sh.el
index f31d3615884..761f594b6b9 100644
--- a/lisp/net/tramp-sh.el
+++ b/lisp/net/tramp-sh.el
@@ -1481,13 +1481,17 @@ of."
(defun tramp-sh-handle-set-file-modes (filename mode &optional flag)
"Like `set-file-modes' for Tramp files."
(with-parsed-tramp-file-name filename nil
- (tramp-flush-file-properties v localname)
- flag ;; FIXME: Support 'nofollow'.
- ;; FIXME: extract the proper text from chmod's stderr.
- (tramp-barf-unless-okay
- v
- (format "chmod %o %s" mode (tramp-shell-quote-argument localname))
- "Error while changing file's mode %s" filename)))
+ (let ((chmod "chmod"))
+ (when (and (eq flag 'nofollow) (file-symlink-p filename))
+ (or (setq chmod (tramp-get-remote-chmod-h v))
+ (tramp-error
+ v 'file-error "Cannot chmod %s with %s flag" filename flag)))
+ (tramp-flush-file-properties v localname)
+ ;; FIXME: extract the proper text from chmod's stderr.
+ (tramp-barf-unless-okay
+ v
+ (format "%s %o %s" chmod mode (tramp-shell-quote-argument localname))
+ "Error while changing file's mode %s" filename))))
(defun tramp-sh-handle-set-file-times (filename &optional time)
"Like `set-file-times' for Tramp files."
@@ -2280,7 +2284,7 @@ the uid and gid from FILENAME."
;; We must change the ownership as local user.
;; Since this does not work reliable, we also
;; give read permissions.
- (set-file-modes tmpfile #o0777 'nofollow)
+ (set-file-modes tmpfile #o0777)
(tramp-set-file-uid-gid
tmpfile
(tramp-get-remote-uid v 'integer)
@@ -3222,8 +3226,7 @@ STDERR can also be a file name."
(delete-file tmpfile2)))))
;; Set proper permissions.
- (set-file-modes tmpfile (tramp-default-file-modes filename)
- 'nofollow)
+ (set-file-modes tmpfile (tramp-default-file-modes filename))
;; Set local user ownership.
(tramp-set-file-uid-gid tmpfile))
@@ -3272,7 +3275,8 @@ STDERR can also be a file name."
#'write-region
(list start end localname append 'no-message lockname))
- (let* ((modes (save-excursion (tramp-default-file-modes filename)))
+ (let* ((modes (tramp-default-file-modes
+ filename (and (eq mustbenew 'excl) 'nofollow)))
;; We use this to save the value of
;; `last-coding-system-used' after writing the tmp
;; file. At the end of the function, we set
@@ -3322,7 +3326,7 @@ STDERR can also be a file name."
;; handles permissions.
;; Ensure that it is still readable.
(when modes
- (set-file-modes tmpfile (logior (or modes 0) #o0400) 'nofollow))
+ (set-file-modes tmpfile (logior (or modes 0) #o0400)))
;; This is a bit lengthy due to the different methods
;; possible for file transfer. First, we check whether the
@@ -5897,6 +5901,22 @@ ID-FORMAT valid values are `string' and `integer'."
vec (concat command " -A n </dev/null"))
command)))))
+(defun tramp-get-remote-chmod-h (vec)
+ "Determine remote `chmod' command which supports nofollow argument."
+ (with-tramp-connection-property vec "chmod-h"
+ (tramp-message vec 5 "Finding a suitable `chmod' command with nofollow")
+ (let ((tmpfile
+ (make-temp-name
+ (expand-file-name
+ tramp-temp-name-prefix (tramp-get-remote-tmpdir vec)))))
+ (when (tramp-send-command-and-check
+ vec
+ (format
+ "ln -s foo %s && chmod -h %s 0777"
+ (tramp-file-local-name tmpfile) (tramp-file-local-name tmpfile)))
+ (delete-file tmpfile)
+ "chmod -h"))))
+
(defun tramp-get-env-with-u-option (vec)
"Check, whether the remote `env' command supports the -u option."
(with-tramp-connection-property vec "env-u-option"
diff --git a/lisp/net/tramp-smb.el b/lisp/net/tramp-smb.el
index 95505ea101f..abd369f5029 100644
--- a/lisp/net/tramp-smb.el
+++ b/lisp/net/tramp-smb.el
@@ -1466,8 +1466,9 @@ component is used as the target of the symlink."
(defun tramp-smb-handle-set-file-modes (filename mode &optional flag)
"Like `set-file-modes' for Tramp files."
- flag ;; FIXME: Support 'nofollow'.
(with-parsed-tramp-file-name filename nil
+ (when (and (eq flag 'nofollow) (file-symlink-p filename))
+ (tramp-error v 'file-error "Cannot chmod %s with %s flag" filename flag))
(when (tramp-smb-get-cifs-capabilities v)
(tramp-flush-file-properties v localname)
(unless (tramp-smb-send-command
diff --git a/lisp/net/tramp-sudoedit.el b/lisp/net/tramp-sudoedit.el
index 4654d633fab..e70ee4ef79f 100644
--- a/lisp/net/tramp-sudoedit.el
+++ b/lisp/net/tramp-sudoedit.el
@@ -465,8 +465,9 @@ the result will be a local, non-Tramp, file name."
(defun tramp-sudoedit-handle-set-file-modes (filename mode &optional flag)
"Like `set-file-modes' for Tramp files."
- flag ;; FIXME: Support 'nofollow'.
(with-parsed-tramp-file-name filename nil
+ (when (and (eq flag 'nofollow) (file-symlink-p filename))
+ (tramp-error v 'file-error "Cannot chmod %s with %s flag" filename flag))
(tramp-flush-file-properties v localname)
(unless (tramp-sudoedit-send-command
v "chmod" (format "%o" mode)
@@ -716,13 +717,14 @@ ID-FORMAT valid values are `string' and `integer'."
(start end filename &optional append visit lockname mustbenew)
"Like `write-region' for Tramp files."
(with-parsed-tramp-file-name filename nil
- (let ((uid (or (tramp-compat-file-attribute-user-id
- (file-attributes filename 'integer))
- (tramp-sudoedit-get-remote-uid v 'integer)))
- (gid (or (tramp-compat-file-attribute-group-id
- (file-attributes filename 'integer))
- (tramp-sudoedit-get-remote-gid v 'integer)))
- (modes (tramp-default-file-modes filename)))
+ (let* ((uid (or (tramp-compat-file-attribute-user-id
+ (file-attributes filename 'integer))
+ (tramp-sudoedit-get-remote-uid v 'integer)))
+ (gid (or (tramp-compat-file-attribute-group-id
+ (file-attributes filename 'integer))
+ (tramp-sudoedit-get-remote-gid v 'integer)))
+ (flag (and (eq mustbenew 'excl) 'nofollow))
+ (modes (tramp-default-file-modes filename flag)))
(prog1
(tramp-handle-write-region
start end filename append visit lockname mustbenew)
@@ -736,8 +738,7 @@ ID-FORMAT valid values are `string' and `integer'."
(file-attributes filename 'integer))
gid))
(tramp-set-file-uid-gid filename uid gid))
- (set-file-modes filename modes
- (when (eq mustbenew 'excl) 'nofollow))))))
+ (tramp-compat-set-file-modes filename modes flag)))))
;; Internal functions.
diff --git a/lisp/net/tramp.el b/lisp/net/tramp.el
index 64acaa95d47..c498f8c25e7 100644
--- a/lisp/net/tramp.el
+++ b/lisp/net/tramp.el
@@ -2135,11 +2135,13 @@ For definition of that list see `tramp-set-completion-function'."
(defvar tramp-devices 0
"Keeps virtual device numbers.")
-(defun tramp-default-file-modes (filename)
+(defun tramp-default-file-modes (filename &optional flag)
"Return file modes of FILENAME as integer.
-If the file modes of FILENAME cannot be determined, return the
-value of `default-file-modes', without execute permissions."
- (or (file-modes filename)
+If optional FLAG is ‘nofollow’, do not follow FILENAME if it is a
+symbolic link. If the file modes of FILENAME cannot be
+determined, return the value of `default-file-modes', without
+execute permissions."
+ (or (tramp-compat-file-modes filename flag)
(logand (default-file-modes) #o0666)))
(defun tramp-replace-environment-variables (filename)
@@ -3181,11 +3183,11 @@ User is always nil."
(defun tramp-handle-file-modes (filename &optional flag)
"Like `file-modes' for Tramp files."
- (when-let ((attrs (file-attributes filename)))
- (let ((mode-string (tramp-compat-file-attribute-modes attrs)))
- (if (and (not flag) (eq ?l (aref mode-string 0)))
- (tramp-handle-file-modes (file-chase-links filename) 'nofollow)
- (tramp-mode-string-to-int mode-string)))))
+ (when-let ((attrs (file-attributes filename))
+ (mode-string (tramp-compat-file-attribute-modes attrs)))
+ (if (and (not (eq flag 'nofollow)) (eq ?l (aref mode-string 0)))
+ (file-modes (file-truename filename))
+ (tramp-mode-string-to-int mode-string))))
;; Localname manipulation functions that grok Tramp localnames...
(defun tramp-handle-file-name-as-directory (file)
@@ -3879,7 +3881,8 @@ of."
(tramp-error v 'file-already-exists filename))
(let ((tmpfile (tramp-compat-make-temp-file filename))
- (modes (save-excursion (tramp-default-file-modes filename))))
+ (modes (tramp-default-file-modes
+ filename (and (eq mustbenew 'excl) 'nofollow))))
(when (and append (file-exists-p filename))
(copy-file filename tmpfile 'ok))
;; The permissions of the temporary file should be set. If
@@ -3887,7 +3890,7 @@ of."
;; 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) 'nofollow)
+ (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.
@@ -4667,7 +4670,7 @@ Return the local name of the temporary file."
(setq result nil)
;; This creates the file by side effect.
(set-file-times result)
- (set-file-modes result #o0700 'nofollow)))
+ (set-file-modes result #o0700)))
;; Return the local part.
(tramp-file-local-name result)))