* 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'.
(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)
"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)))))))
(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.
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"
;; 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.
;; 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."
"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)))))
(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."
(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)
(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
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.
(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"
(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"
"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."
(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."
"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."
(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."
(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."
((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))
(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.
(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.
(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))