[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
master 684950eb94: Make call of remote `id' more performant in Tramp
From: |
Michael Albinus |
Subject: |
master 684950eb94: Make call of remote `id' more performant in Tramp |
Date: |
Thu, 8 Sep 2022 04:36:18 -0400 (EDT) |
branch: master
commit 684950eb945064b8273109fc165818edd470da32
Author: Michael Albinus <michael.albinus@gmx.de>
Commit: Michael Albinus <michael.albinus@gmx.de>
Make call of remote `id' more performant in Tramp
* lisp/net/tramp-adb.el (tramp-adb-handle-file-exists-p): New defun.
(tramp-adb-file-name-handler-alist): Use it.
(tramp-adb-handle-file-executable-p)
(tramp-adb-handle-file-readable-p)
(tramp-adb-handle-file-writable-p)
(tramp-adb-handle-get-remote-uid)
(tramp-adb-handle-get-remote-gid)
(tramp-adb-handle-get-remote-groups): Use caches consequently.
* lisp/net/tramp-sh.el (tramp-perl-id, tramp-python-id): New defconsts.
(tramp-sh-handle-get-remote-uid, tramp-sh-handle-get-remote-gid)
(tramp-sh-handle-get-remote-groups): Use caches consequently.
(tramp-sh-handle-file-writable-p): Use `file-writable-p'.
(tramp-expand-script): Handle also "python" expansion.
(tramp-get-remote-id): Do not set connection property anymore,
this is done differently now.
(tramp-get-remote-uid-with-id, tramp-get-remote-uid-with-perl)
(tramp-get-remote-uid-with-python, tramp-get-remote-gid-with-id)
(tramp-get-remote-gid-with-perl)
(tramp-get-remote-gid-with-python): Remove.
* lisp/net/tramp-sudoedit.el (tramp-sudoedit-handle-file-executable-p)
(tramp-sudoedit-handle-file-exists-p)
(tramp-sudoedit-handle-file-readable-p)
(tramp-sudoedit-handle-file-writable-p):
(tramp-sudoedit-handle-get-remote-uid)
(tramp-sudoedit-handle-get-remote-gid)
(tramp-sudoedit-handle-get-remote-groups): Use caches consequently.
* lisp/net/tramp.el (tramp-check-cached-permissions):
Call `tramp-get-remote-groups' only if needed.
(tramp-get-remote-groups): Do not return default value.
(tramp-read-id-output): New defun.
* test/lisp/net/tramp-tests.el (tramp--test-deftest-with-perl):
Suppress also remote `id'.
---
lisp/net/tramp-adb.el | 92 ++++++++++-----------
lisp/net/tramp-sh.el | 189 +++++++++++++++++++------------------------
lisp/net/tramp-sudoedit.el | 75 ++++++++---------
lisp/net/tramp.el | 54 ++++++++++---
test/lisp/net/tramp-tests.el | 4 +-
5 files changed, 209 insertions(+), 205 deletions(-)
diff --git a/lisp/net/tramp-adb.el b/lisp/net/tramp-adb.el
index 3fb28d91ea..dfb026f834 100644
--- a/lisp/net/tramp-adb.el
+++ b/lisp/net/tramp-adb.el
@@ -127,7 +127,7 @@ It is used for TCP/IP devices."
(file-directory-p . tramp-handle-file-directory-p)
(file-equal-p . tramp-handle-file-equal-p)
(file-executable-p . tramp-adb-handle-file-executable-p)
- (file-exists-p . tramp-handle-file-exists-p)
+ (file-exists-p . tramp-adb-handle-file-exists-p)
(file-in-directory-p . tramp-handle-file-in-directory-p)
(file-local-copy . tramp-adb-handle-file-local-copy)
(file-locked-p . tramp-handle-file-locked-p)
@@ -489,24 +489,50 @@ Emacs dired can't find files."
"Like `file-executable-p' for Tramp files."
(with-parsed-tramp-file-name filename nil
(with-tramp-file-property v localname "file-executable-p"
- (tramp-adb-send-command-and-check
- v (format "test -x %s" (tramp-shell-quote-argument localname))))))
+ ;; Examine `file-attributes' cache to see if request can be
+ ;; satisfied without remote operation.
+ (if (tramp-file-property-p v localname "file-attributes")
+ (or (tramp-check-cached-permissions v ?x)
+ (tramp-check-cached-permissions v ?s))
+ (tramp-adb-send-command-and-check
+ v (format "test -x %s" (tramp-shell-quote-argument localname)))))))
+
+(defun tramp-adb-handle-file-exists-p (filename)
+ "Like `file-exists-p' for Tramp files."
+ ;; `file-exists-p' is used as predicate in file name completion.
+ ;; We don't want to run it when `non-essential' is t, or there is
+ ;; no connection process yet.
+ (when (tramp-connectable-p filename)
+ (with-parsed-tramp-file-name filename nil
+ (with-tramp-file-property v localname "file-exists-p"
+ (if (tramp-file-property-p v localname "file-attributes")
+ (not (null (tramp-get-file-property v localname "file-attributes")))
+ (tramp-adb-send-command-and-check
+ v (format "test -e %s" (tramp-shell-quote-argument localname))))))))
(defun tramp-adb-handle-file-readable-p (filename)
"Like `file-readable-p' for Tramp files."
(with-parsed-tramp-file-name filename nil
(with-tramp-file-property v localname "file-readable-p"
- (or (tramp-handle-file-readable-p filename)
- (tramp-adb-send-command-and-check
- v (format "test -r %s" (tramp-shell-quote-argument localname)))))))
+ ;; Examine `file-attributes' cache to see if request can be
+ ;; satisfied without remote operation.
+ (if (tramp-file-property-p v localname "file-attributes")
+ (tramp-handle-file-readable-p filename)
+ (tramp-adb-send-command-and-check
+ v (format "test -r %s" (tramp-shell-quote-argument localname)))))))
(defun tramp-adb-handle-file-writable-p (filename)
"Like `file-writable-p' for Tramp files."
(with-parsed-tramp-file-name filename nil
(with-tramp-file-property v localname "file-writable-p"
(if (file-exists-p filename)
- (tramp-adb-send-command-and-check
- v (format "test -w %s" (tramp-shell-quote-argument localname)))
+ (if (tramp-file-property-p v localname "file-attributes")
+ ;; Examine `file-attributes' cache to see if request can
+ ;; be satisfied without remote operation.
+ (tramp-check-cached-permissions v ?w)
+ (tramp-adb-send-command-and-check
+ v (format "test -w %s" (tramp-shell-quote-argument localname))))
+ ;; If file doesn't exist, check if directory is writable.
(and
(file-directory-p (file-name-directory filename))
(file-writable-p (file-name-directory filename)))))))
@@ -1040,57 +1066,23 @@ implementation will be used."
(defun tramp-adb-handle-get-remote-uid (vec id-format)
"Like `tramp-get-remote-uid' for Tramp files.
ID-FORMAT valid values are `string' and `integer'."
- ;; The result is cached in `tramp-get-remote-uid'.
- (tramp-adb-send-command
- vec
- (format "id -u%s %s"
- (if (equal id-format 'integer) "" "n")
- (if (equal id-format 'integer)
- "" "| sed -e s/^/\\\"/ -e s/\\$/\\\"/")))
- (with-current-buffer (tramp-get-connection-buffer vec)
- ;; Read the expression.
- (goto-char (point-min))
- (read (current-buffer))))
+ (tramp-adb-send-command vec "id")
+ (tramp-read-id-output vec)
+ (tramp-get-connection-property vec (format "uid-%s" id-format)))
(defun tramp-adb-handle-get-remote-gid (vec id-format)
"Like `tramp-get-remote-gid' for Tramp files.
ID-FORMAT valid values are `string' and `integer'."
- ;; The result is cached in `tramp-get-remote-gid'.
- (tramp-adb-send-command
- vec
- (format "id -g%s %s"
- (if (equal id-format 'integer) "" "n")
- (if (equal id-format 'integer)
- "" "| sed -e s/^/\\\"/ -e s/\\$/\\\"/")))
- (with-current-buffer (tramp-get-connection-buffer vec)
- ;; Read the expression.
- (goto-char (point-min))
- (read (current-buffer))))
+ (tramp-adb-send-command vec "id")
+ (tramp-read-id-output vec)
+ (tramp-get-connection-property vec (format "gid-%s" id-format)))
(defun tramp-adb-handle-get-remote-groups (vec id-format)
"Like `tramp-get-remote-groups' for Tramp files.
ID-FORMAT valid values are `string' and `integer'."
- ;; The result is cached in `tramp-get-remote-groups'.
(tramp-adb-send-command vec "id")
- (with-current-buffer (tramp-get-connection-buffer vec)
- (let (groups-integer groups-string)
- ;; Read the expression.
- (goto-char (point-min))
- (when (re-search-forward (rx bol (+ nonl) "groups=") nil 'noerror)
- (while (looking-at
- (rx (group (+ digit)) "(" (group (+ (any "_" word))) ")"))
- (setq groups-integer (cons (string-to-number (match-string 1))
- groups-integer)
- groups-string (cons (match-string 2) groups-string))
- (goto-char (match-end 0))
- (skip-chars-forward ",")))
- (tramp-set-connection-property
- vec "groups-integer"
- (setq groups-integer (nreverse groups-integer)))
- (tramp-set-connection-property
- vec "groups-string"
- (setq groups-string (nreverse groups-string)))
- (if (eq id-format 'integer) groups-integer groups-string))))
+ (tramp-read-id-output vec)
+ (tramp-get-connection-property vec (format "groups-%s" id-format)))
(defun tramp-adb-get-device (vec)
"Return full host name from VEC to be used in shell execution.
diff --git a/lisp/net/tramp-sh.el b/lisp/net/tramp-sh.el
index ff153d955b..a783f8c16c 100644
--- a/lisp/net/tramp-sh.el
+++ b/lisp/net/tramp-sh.el
@@ -783,6 +783,41 @@ characters need to be doubled.")
Format specifiers are replaced by `tramp-expand-script', percent
characters need to be doubled.")
+(defconst tramp-perl-id
+ "%p -e '
+use strict;
+use warnings;
+use POSIX qw(getgroups);
+
+my ($user, $passwd, $uid, $gid) = getpwuid $< ;
+my $group = getgrgid $gid ;
+my @groups = map { $_ . \"(\" . getgrgid ($_) . \")\" } getgroups ();
+
+printf \"uid=%%d(%%s) gid=%%d(%%s) groups=%%s\\n\",
+ $uid, $user, $gid, $group, join \",\", @groups;' %n"
+ "Perl script printing `id' output.
+Format specifiers are replaced by `tramp-expand-script', percent
+characters need to be doubled.")
+
+(defconst tramp-python-id
+ "%y -c '
+import os, pwd, grp;
+
+def idform(id):
+ return \"{:d}({:s})\".format(id, grp.getgrgid(id)[0]);
+
+uid = os.getuid();
+user = pwd.getpwuid(uid)[0];
+gid = os.getgid();
+group = grp.getgrgid(gid)[0]
+groups = map(idform, os.getgrouplist(user, gid));
+
+print(\"uid={:d}({:s}) gid={:d}({:s}) groups={:s}\"
+ .format(uid, user, gid, group, \",\".join(groups)));' %n"
+ "Python script printing `id' output.
+Format specifiers are replaced by `tramp-expand-script', percent
+characters need to be doubled.")
+
;; These two use base64 encoding.
(defconst tramp-perl-encode-with-module
"%p -MMIME::Base64 -0777 -ne 'print encode_base64($_)' %n"
@@ -1524,10 +1559,16 @@ ID-FORMAT valid values are `string' and `integer'."
;; The result is cached in `tramp-get-remote-uid'.
(ignore-errors
(cond
- ((tramp-get-remote-id vec) (tramp-get-remote-uid-with-id vec id-format))
- ((tramp-get-remote-perl vec) (tramp-get-remote-uid-with-perl vec
id-format))
+ ((tramp-get-remote-id vec)
+ (tramp-send-command vec (tramp-get-remote-id vec)))
+ ((tramp-get-remote-perl vec)
+ (tramp-maybe-send-script vec tramp-perl-id "tramp_perl_id")
+ (tramp-send-command vec "tramp_perl_id"))
((tramp-get-remote-python vec)
- (tramp-get-remote-uid-with-python vec id-format)))))
+ (tramp-maybe-send-script vec tramp-python-id "tramp_python_id")
+ (tramp-send-command vec "tramp_python_id")))
+ (tramp-read-id-output vec)
+ (tramp-get-connection-property vec (format "uid-%s" id-format))))
(defun tramp-sh-handle-get-remote-gid (vec id-format)
"The gid of the remote connection VEC, in ID-FORMAT.
@@ -1535,36 +1576,33 @@ ID-FORMAT valid values are `string' and `integer'."
;; The result is cached in `tramp-get-remote-gid'.
(ignore-errors
(cond
- ((tramp-get-remote-id vec) (tramp-get-remote-gid-with-id vec id-format))
- ((tramp-get-remote-perl vec) (tramp-get-remote-gid-with-perl vec
id-format))
+ ((tramp-get-remote-id vec)
+ (tramp-send-command vec (tramp-get-remote-id vec)))
+ ((tramp-get-remote-perl vec)
+ (tramp-maybe-send-script vec tramp-perl-id "tramp_perl_id")
+ (tramp-send-command vec "tramp_perl_id"))
((tramp-get-remote-python vec)
- (tramp-get-remote-gid-with-python vec id-format)))))
+ (tramp-maybe-send-script vec tramp-python-id "tramp_python_id")
+ (tramp-send-command vec "tramp_python_id")))
+ (tramp-read-id-output vec)
+ (tramp-get-connection-property vec (format "gid-%s" id-format))))
(defun tramp-sh-handle-get-remote-groups (vec id-format)
"Like `tramp-get-remote-groups' for Tramp files.
ID-FORMAT valid values are `string' and `integer'."
;; The result is cached in `tramp-get-remote-groups'.
- (when (tramp-get-remote-id vec)
- (tramp-send-command vec (tramp-get-remote-id vec)))
- (with-current-buffer (tramp-get-connection-buffer vec)
- (let (groups-integer groups-string)
- ;; Read the expression.
- (goto-char (point-min))
- (when (re-search-forward (rx bol (+ nonl) "groups=") nil 'noerror)
- (while (looking-at
- (rx (group (+ digit)) "(" (group (+ (any "_" word))) ")"))
- (setq groups-integer (cons (string-to-number (match-string 1))
- groups-integer)
- groups-string (cons (match-string 2) groups-string))
- (goto-char (match-end 0))
- (skip-chars-forward ",")))
- (tramp-set-connection-property
- vec "groups-integer"
- (setq groups-integer (nreverse groups-integer)))
- (tramp-set-connection-property
- vec "groups-string"
- (setq groups-string (nreverse groups-string)))
- (if (eq id-format 'integer) groups-integer groups-string))))
+ (ignore-errors
+ (cond
+ ((tramp-get-remote-id vec)
+ (tramp-send-command vec (tramp-get-remote-id vec)))
+ ((tramp-get-remote-perl vec)
+ (tramp-maybe-send-script vec tramp-perl-id "tramp_perl_id")
+ (tramp-send-command vec "tramp_perl_id"))
+ ((tramp-get-remote-python vec)
+ (tramp-maybe-send-script vec tramp-python-id "tramp_python_id")
+ (tramp-send-command vec "tramp_python_id")))
+ (tramp-read-id-output vec)
+ (tramp-get-connection-property vec (format "groups-%s" id-format))))
(defun tramp-sh-handle-set-file-uid-gid (filename &optional uid gid)
"Like `tramp-set-file-uid-gid' for Tramp files."
@@ -1694,6 +1732,8 @@ ID-FORMAT valid values are `string' and `integer'."
"Like `file-readable-p' for Tramp files."
(with-parsed-tramp-file-name filename nil
(with-tramp-file-property v localname "file-readable-p"
+ ;; Examine `file-attributes' cache to see if request can be
+ ;; satisfied without remote operation.
(if (tramp-file-property-p v localname "file-attributes")
(tramp-handle-file-readable-p filename)
(tramp-run-test "-r" filename)))))
@@ -1730,8 +1770,9 @@ ID-FORMAT valid values are `string' and `integer'."
(tramp-check-cached-permissions v ?w)
(tramp-run-test "-w" filename))
;; If file doesn't exist, check if directory is writable.
- (and (file-exists-p (file-name-directory filename))
- (tramp-run-test "-w" (file-name-directory filename)))))))
+ (and
+ (file-directory-p (file-name-directory filename))
+ (file-writable-p (file-name-directory filename)))))))
(defun tramp-sh-handle-file-ownership-preserved-p (filename &optional group)
"Like `file-ownership-preserved-p' for Tramp files."
@@ -3971,15 +4012,15 @@ Fall back to normal file name handler if no Tramp
handler exists."
(defun tramp-expand-script (vec script)
"Expand SCRIPT with remote files or commands.
-\"%a\", \"%h\", \"%l\", \"%o\", \"%p\", \"%r\" and \"%s\" format
-specifiers are replaced by the respective `awk', `hexdump', `ls',
-`od', `perl', `readlink' and `stat' commands. \"%n\" is replaced
-by \"2>/dev/null\", and \"%t\" is replaced by a temporary file
-name. If VEC is nil, the respective local commands are used. If
-there is a format specifier which cannot be expanded, this
-function returns nil."
+\"%a\", \"%h\", \"%l\", \"%o\", \"%p\", \"%r\", \"%s\" and \"%y\"
+format specifiers are replaced by the respective `awk',
+`hexdump', `ls', `od', `perl', `readlink', `stat' and `python'
+commands. \"%n\" is replaced by \"2>/dev/null\", and \"%t\" is
+replaced by a temporary file name. If VEC is nil, the respective
+local commands are used. If there is a format specifier which
+cannot be expanded, this function returns nil."
(if (not (string-match-p
- (rx (| bol (not (any "%"))) "%" (any "ahlnoprst")) script))
+ (rx (| bol (not (any "%"))) "%" (any "ahlnoprsty")) script))
script
(catch 'wont-work
(let ((awk (when (string-match-p (rx (| bol (not (any "%"))) "%a")
script)
@@ -4010,6 +4051,11 @@ function returns nil."
(if vec
(tramp-get-remote-perl vec) (executable-find "perl"))
(throw 'wont-work nil))))
+ (python (when (string-match-p (rx (| bol (not (any "%"))) "%y")
script)
+ (or
+ (if vec
+ (tramp-get-remote-python vec) (executable-find
"python"))
+ (throw 'wont-work nil))))
(readlink (when (string-match-p
(rx (| bol (not (any "%"))) "%r") script)
(or
@@ -4032,7 +4078,7 @@ function returns nil."
script
(format-spec-make
?a awk ?h hdmp ?l ls ?n dev ?o od ?p perl
- ?r readlink ?s stat ?t tmp))))))
+ ?r readlink ?s stat ?t tmp ?y python))))))
(defun tramp-maybe-send-script (vec script name)
"Define in remote shell function NAME implemented as SCRIPT.
@@ -5816,36 +5862,9 @@ This command is returned only if
`delete-by-moving-to-trash' is non-nil."
(while (and dl (setq result (tramp-find-executable vec cmd dl t t)))
;; Check POSIX parameter.
(when (tramp-send-command-and-check vec (format "%s -u" result))
- (tramp-set-connection-property
- vec "uid-integer"
- (with-current-buffer (tramp-get-connection-buffer vec)
- (goto-char (point-min))
- (read (current-buffer))))
(throw 'id-found result))
(setq dl (cdr dl))))))))
-(defun tramp-get-remote-uid-with-id (vec id-format)
- "Implement `tramp-get-remote-uid' for Tramp files using `id'."
- ;; `tramp-get-remote-id' sets already connection property "uid-integer".
- (with-tramp-connection-property vec (format "uid-%s" id-format)
- (tramp-send-command-and-read
- vec
- (format "%s -u%s %s"
- (tramp-get-remote-id vec)
- (if (equal id-format 'integer) "" "n")
- (if (equal id-format 'integer)
- "" "| sed -e s/^/\\\"/ -e s/\\$/\\\"/")))))
-
-(defun tramp-get-remote-uid-with-perl (vec id-format)
- "Implement `tramp-get-remote-uid' for Tramp files using a Perl script."
- (tramp-send-command-and-read
- vec
- (format "%s -le '%s'"
- (tramp-get-remote-perl vec)
- (if (equal id-format 'integer)
- "print $>"
- "print \"\\\"\", scalar getpwuid($>), \"\\\"\""))))
-
(defun tramp-get-remote-python (vec)
"Determine remote `python' command."
(with-tramp-connection-property vec "python"
@@ -5853,46 +5872,6 @@ This command is returned only if
`delete-by-moving-to-trash' is non-nil."
(or (tramp-find-executable vec "python" (tramp-get-remote-path vec))
(tramp-find-executable vec "python3" (tramp-get-remote-path vec)))))
-(defun tramp-get-remote-uid-with-python (vec id-format)
- "Implement `tramp-get-remote-uid' for Tramp files using `python'."
- (tramp-send-command-and-read
- vec
- (format "%s -c \"%s\""
- (tramp-get-remote-python vec)
- (if (equal id-format 'integer)
- "import os; print (os.getuid())"
- "import os, pwd; print ('\\\"' + pwd.getpwuid(os.getuid())[0] +
'\\\"')"))))
-
-(defun tramp-get-remote-gid-with-id (vec id-format)
- "Implement `tramp-get-remote-gid' for Tramp files using `id'."
- (tramp-send-command-and-read
- vec
- (format "%s -g%s %s"
- (tramp-get-remote-id vec)
- (if (equal id-format 'integer) "" "n")
- (if (equal id-format 'integer)
- "" "| sed -e s/^/\\\"/ -e s/\\$/\\\"/"))))
-
-(defun tramp-get-remote-gid-with-perl (vec id-format)
- "Implement `tramp-get-remote-gid' for Tramp files using a Perl script."
- (tramp-send-command-and-read
- vec
- (format "%s -le '%s'"
- (tramp-get-remote-perl vec)
- (if (equal id-format 'integer)
- "print ($)=~/(\\d+)/)"
- "print \"\\\"\", scalar getgrgid($)), \"\\\"\""))))
-
-(defun tramp-get-remote-gid-with-python (vec id-format)
- "Implement `tramp-get-remote-gid' for Tramp files using `python'."
- (tramp-send-command-and-read
- vec
- (format "%s -c \"%s\""
- (tramp-get-remote-python vec)
- (if (equal id-format 'integer)
- "import os; print (os.getgid())"
- "import os, grp; print ('\\\"' + grp.getgrgid(os.getgid())[0] +
'\\\"')"))))
-
(defun tramp-get-remote-busybox (vec)
"Determine remote `busybox' command."
(with-tramp-connection-property vec "busybox"
diff --git a/lisp/net/tramp-sudoedit.el b/lisp/net/tramp-sudoedit.el
index ef0954ab83..e0b577fff8 100644
--- a/lisp/net/tramp-sudoedit.el
+++ b/lisp/net/tramp-sudoedit.el
@@ -442,8 +442,13 @@ the result will be a local, non-Tramp, file name."
"Like `file-executable-p' for Tramp files."
(with-parsed-tramp-file-name filename nil
(with-tramp-file-property v localname "file-executable-p"
- (tramp-sudoedit-send-command
- v "test" "-x" (tramp-compat-file-name-unquote localname)))))
+ ;; Examine `file-attributes' cache to see if request can be
+ ;; satisfied without remote operation.
+ (if (tramp-file-property-p v localname "file-attributes")
+ (or (tramp-check-cached-permissions v ?x)
+ (tramp-check-cached-permissions v ?s))
+ (tramp-sudoedit-send-command
+ v "test" "-x" (tramp-compat-file-name-unquote localname))))))
(defun tramp-sudoedit-handle-file-exists-p (filename)
"Like `file-exists-p' for Tramp files."
@@ -453,8 +458,10 @@ the result will be a local, non-Tramp, file name."
(when (tramp-connectable-p filename)
(with-parsed-tramp-file-name filename nil
(with-tramp-file-property v localname "file-exists-p"
- (tramp-sudoedit-send-command
- v "test" "-e" (tramp-compat-file-name-unquote localname))))))
+ (if (tramp-file-property-p v localname "file-attributes")
+ (not (null (tramp-get-file-property v localname "file-attributes")))
+ (tramp-sudoedit-send-command
+ v "test" "-e" (tramp-compat-file-name-unquote localname)))))))
(defun tramp-sudoedit-handle-file-name-all-completions (filename directory)
"Like `file-name-all-completions' for Tramp files."
@@ -483,9 +490,12 @@ the result will be a local, non-Tramp, file name."
"Like `file-readable-p' for Tramp files."
(with-parsed-tramp-file-name filename nil
(with-tramp-file-property v localname "file-readable-p"
- (or (tramp-handle-file-readable-p filename)
- (tramp-sudoedit-send-command
- v "test" "-r" (tramp-compat-file-name-unquote localname))))))
+ ;; Examine `file-attributes' cache to see if request can be
+ ;; satisfied without remote operation.
+ (if (tramp-file-property-p v localname "file-attributes")
+ (tramp-handle-file-readable-p filename)
+ (tramp-sudoedit-send-command
+ v "test" "-r" (tramp-compat-file-name-unquote localname))))))
(defun tramp-sudoedit-handle-set-file-modes (filename mode &optional flag)
"Like `set-file-modes' for Tramp files."
@@ -597,11 +607,16 @@ the result will be a local, non-Tramp, file name."
(with-parsed-tramp-file-name filename nil
(with-tramp-file-property v localname "file-writable-p"
(if (file-exists-p filename)
- (tramp-sudoedit-send-command
- v "test" "-w" (tramp-compat-file-name-unquote localname))
- (let ((dir (file-name-directory filename)))
- (and (file-exists-p dir)
- (file-writable-p dir)))))))
+ (if (tramp-file-property-p v localname "file-attributes")
+ ;; Examine `file-attributes' cache to see if request can
+ ;; be satisfied without remote operation.
+ (tramp-check-cached-permissions v ?w)
+ (tramp-sudoedit-send-command
+ v "test" "-w" (tramp-compat-file-name-unquote localname)))
+ ;; If file doesn't exist, check if directory is writable.
+ (and
+ (file-directory-p (file-name-directory filename))
+ (file-writable-p (file-name-directory filename)))))))
(defun tramp-sudoedit-handle-make-directory (dir &optional parents)
"Like `make-directory' for Tramp files."
@@ -720,43 +735,23 @@ VEC or USER, or if there is no home directory, return
nil."
(defun tramp-sudoedit-handle-get-remote-uid (vec id-format)
"The uid of the remote connection VEC, in ID-FORMAT.
ID-FORMAT valid values are `string' and `integer'."
- ;; The result is cached in `tramp-get-remote-uid'.
- (if (equal id-format 'integer)
- (tramp-sudoedit-send-command-and-read vec "id" "-u")
- (tramp-sudoedit-send-command-string vec "id" "-un")))
+ (tramp-sudoedit-send-command vec "id")
+ (tramp-read-id-output vec)
+ (tramp-get-connection-property vec (format "uid-%s" id-format)))
(defun tramp-sudoedit-handle-get-remote-gid (vec id-format)
"The gid of the remote connection VEC, in ID-FORMAT.
ID-FORMAT valid values are `string' and `integer'."
- ;; The result is cached in `tramp-get-remote-gid'.
- (if (equal id-format 'integer)
- (tramp-sudoedit-send-command-and-read vec "id" "-g")
- (tramp-sudoedit-send-command-string vec "id" "-gn")))
+ (tramp-sudoedit-send-command vec "id")
+ (tramp-read-id-output vec)
+ (tramp-get-connection-property vec (format "gid-%s" id-format)))
(defun tramp-sudoedit-handle-get-remote-groups (vec id-format)
"Like `tramp-get-remote-groups' for Tramp files.
ID-FORMAT valid values are `string' and `integer'."
- ;; The result is cached in `tramp-get-remote-groups'.
(tramp-sudoedit-send-command vec "id")
- (with-current-buffer (tramp-get-connection-buffer vec)
- (let (groups-integer groups-string)
- ;; Read the expression.
- (goto-char (point-min))
- (when (re-search-forward (rx bol (+ nonl) "groups=") nil 'noerror)
- (while (looking-at
- (rx (group (+ digit)) "(" (group (+ (any "_" word))) ")"))
- (setq groups-integer (cons (string-to-number (match-string 1))
- groups-integer)
- groups-string (cons (match-string 2) groups-string))
- (goto-char (match-end 0))
- (skip-chars-forward ",")))
- (tramp-set-connection-property
- vec "groups-integer"
- (setq groups-integer (nreverse groups-integer)))
- (tramp-set-connection-property
- vec "groups-string"
- (setq groups-string (nreverse groups-string)))
- (if (eq id-format 'integer) groups-integer groups-string))))
+ (tramp-read-id-output vec)
+ (tramp-get-connection-property vec (format "groups-%s" id-format)))
(defun tramp-sudoedit-handle-set-file-uid-gid (filename &optional uid gid)
"Like `tramp-set-file-uid-gid' for Tramp files."
diff --git a/lisp/net/tramp.el b/lisp/net/tramp.el
index cfc005d270..cd68801c21 100644
--- a/lisp/net/tramp.el
+++ b/lisp/net/tramp.el
@@ -5838,8 +5838,7 @@ be granted."
((eq ?s access) 3)))
(file-attr (file-attributes (tramp-make-tramp-file-name vec)))
(remote-uid (tramp-get-remote-uid vec 'integer))
- (remote-gid (tramp-get-remote-gid vec 'integer))
- (remote-groups (tramp-get-remote-groups vec 'integer)))
+ (remote-gid (tramp-get-remote-gid vec 'integer)))
(or
;; Not a symlink.
(eq t (file-attribute-type file-attr))
@@ -5867,7 +5866,8 @@ be granted."
(and
(eq access
(aref (file-attribute-modes file-attr) (+ offset 3)))
- (member (file-attribute-group-id file-attr) remote-groups)))))
+ (member (file-attribute-group-id file-attr)
+ (tramp-get-remote-groups vec 'integer))))))
(defmacro tramp-convert-file-attributes (vec localname id-format attr)
"Convert `file-attributes' ATTR generated Tramp backend functions.
@@ -6008,12 +6008,48 @@ ID-FORMAT valid values are `string' and `integer'."
(defun tramp-get-remote-groups (vec id-format)
"The list of groups of the remote connection VEC, in ID-FORMAT.
ID-FORMAT valid values are `string' and `integer'."
- (or (and (tramp-file-name-p vec)
- (with-tramp-connection-property vec (format "groups-%s" id-format)
- (tramp-file-name-handler #'tramp-get-remote-groups vec id-format)))
- ;; Ensure there is a valid result.
- (and (equal id-format 'integer) (list tramp-unknown-id-integer))
- (and (equal id-format 'string) (list tramp-unknown-id-string))))
+ (and (tramp-file-name-p vec)
+ (with-tramp-connection-property vec (format "groups-%s" id-format)
+ (tramp-file-name-handler #'tramp-get-remote-groups vec id-format))))
+
+(defun tramp-read-id-output (vec)
+ "Read in connection buffer the output of the `id' command.
+Set connection properties \"{uid,gid.groups}-{integer,string}\"."
+ (with-current-buffer (tramp-get-connection-buffer vec)
+ (let (uid-integer uid-string
+ gid-integer gid-string
+ groups-integer groups-string)
+ (goto-char (point-min))
+ ;; Read uid.
+ (when (re-search-forward
+ (rx "uid=" (group (+ digit)) "(" (group (+ (any "_" word))) ")")
+ nil 'noerror)
+ (setq uid-integer (string-to-number (match-string 1))
+ uid-string (match-string 2)))
+ ;; Read gid.
+ (when (re-search-forward
+ (rx "gid=" (group (+ digit)) "(" (group (+ (any "_" word))) ")")
+ nil 'noerror)
+ (setq gid-integer (string-to-number (match-string 1))
+ gid-string (match-string 2)))
+ ;; Read groups.
+ (when (re-search-forward (rx "groups=") nil 'noerror)
+ (while (looking-at
+ (rx (group (+ digit)) "(" (group (+ (any "_" word))) ")"))
+ (setq groups-integer (cons (string-to-number (match-string 1))
+ groups-integer)
+ groups-string (cons (match-string 2) groups-string))
+ (goto-char (match-end 0))
+ (skip-chars-forward ",")))
+ ;; Set connection properties.
+ (tramp-set-connection-property vec "uid-integer" uid-integer)
+ (tramp-set-connection-property vec "uid-string" uid-string)
+ (tramp-set-connection-property vec "gid-integer" gid-integer)
+ (tramp-set-connection-property vec "gid-string" gid-string)
+ (tramp-set-connection-property
+ vec "groups-integer" (nreverse groups-integer))
+ (tramp-set-connection-property
+ vec "groups-string" (nreverse groups-string)))))
(defun tramp-local-host-p (vec)
"Return t if this points to the local host, nil otherwise.
diff --git a/test/lisp/net/tramp-tests.el b/test/lisp/net/tramp-tests.el
index f42f6838c8..6f7c6702e7 100644
--- a/test/lisp/net/tramp-tests.el
+++ b/test/lisp/net/tramp-tests.el
@@ -3622,7 +3622,9 @@ This tests also `access-file', `file-readable-p',
(append
'((nil "stat" nil)
;; See `tramp-sh-handle-file-truename'.
- (nil "readlink" nil))
+ (nil "readlink" nil)
+ ;; See `tramp-sh-handle-get-remote-*'.
+ (nil "id" nil))
tramp-connection-properties)))
(progn
(skip-unless (< (ert-test-result-duration result) 300))
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- master 684950eb94: Make call of remote `id' more performant in Tramp,
Michael Albinus <=