@code{file-readable-p}, @code{file-regular-p},
@code{file-remote-p}, @code{file-selinux-context},
@code{file-symlink-p}, @code{file-system-info},
-@code{file-truename}, @code{file-writable-p},
+@code{file-truename}, @code{file-user-uid},
+@code{file-writable-p},
@code{find-backup-file-name},@*
@code{get-file-buffer},
@code{insert-directory},
@code{file-readable-p}, @code{file-regular-p},
@code{file-remote-p}, @code{file-selinux-context},
@code{file-symlink-p}, @code{file-system-info},
-@code{file-truename}, @code{file-writable-p},
+@code{file-truename}, @code{file-user-uid},
+@code{file-writable-p},
@code{find-backup-file-name},
@code{get-file-buffer},
@code{insert-directory},
This function returns the effective @acronym{UID} of the user.
@end defun
+@defun file-user-uid
+This function returns the connection-local value for the user's
+effective @acronym{UID}. If @code{default-directory} is local, this
+is equivalent to @code{user-uid}, but for remote files (@pxref{Remote
+Files, , , emacs, The GNU Emacs Manual}), it will return the
+@acronym{UID} for the user associated with that remote connection; if
+the remote connection has no associated user, it will instead return
+-1.
+@end defun
+
@cindex GID
@defun group-gid
This function returns the effective @acronym{GID} of the Emacs process.
the value will automatically update to reflect the search path on that
host.
+@vindex $UID
+@item $UID
+This returns the effective @acronym{UID} for the current user. This
+variable is connection-aware, so when the current directory is remote,
+its value will be @acronym{UID} for the user associated with that
+remote connection.
+
@vindex $_
@item $_
This refers to the last argument of the last command. With a
copied to the environment, so external commands invoked from
Eshell can consult them to do the right thing.
+@vindex $INSIDE_EMACS
@item $INSIDE_EMACS
This variable indicates to external commands that they are being
invoked from within Emacs so they can adjust their behavior if
This warning can be suppressed using 'with-suppressed-warnings' with
the warning name 'suspicious'.
++++
+** New function 'file-user-uid'.
+This function is like 'user-uid', but is aware of file name handlers,
+so it will return the remote UID for remote files (or -1 if the
+connection has no associated user).
+
\f
* Changes in Emacs 30.1 on Non-Free Operating Systems
(defcustom eshell-prompt-function
(lambda ()
(concat (abbreviate-file-name (eshell/pwd))
- (if (= (user-uid) 0) " # " " $ ")))
+ (if (= (file-user-uid) 0) " # " " $ ")))
"A function that returns the Eshell prompt string.
Make sure to update `eshell-prompt-regexp' so that it will match your
prompt."
("COLUMNS" ,(lambda () (window-body-width nil 'remap)) t t)
("LINES" ,(lambda () (window-body-height nil 'remap)) t t)
("INSIDE_EMACS" eshell-inside-emacs t)
+ ("UID" ,(lambda () (file-user-uid)) nil t)
;; for esh-ext.el
("PATH" (,(lambda () (string-join (eshell-get-path t) (path-separator)))
(file-symlink-p . tramp-handle-file-symlink-p)
(file-system-info . tramp-adb-handle-file-system-info)
(file-truename . tramp-handle-file-truename)
+ (file-user-uid . tramp-handle-file-user-uid)
(file-writable-p . tramp-adb-handle-file-writable-p)
(find-backup-file-name . tramp-handle-find-backup-file-name)
;; `get-file-buffer' performed by default handler.
(file-symlink-p . tramp-handle-file-symlink-p)
(file-system-info . tramp-archive-handle-file-system-info)
(file-truename . tramp-archive-handle-file-truename)
+ (file-user-uid . tramp-archive-handle-file-user-uid)
(file-writable-p . ignore)
(find-backup-file-name . ignore)
;; `get-file-buffer' performed by default handler.
(let ((default-directory (file-name-directory archive)))
(temporary-file-directory))))
+(defun tramp-archive-handle-file-user-uid ()
+ "Like `user-uid' for file archives."
+ (with-parsed-tramp-archive-file-name default-directory nil
+ (let ((default-directory (file-name-directory archive)))
+ (file-user-uid))))
+
(defun tramp-archive-handle-not-implemented (operation &rest args)
"Generic handler for operations not implemented for file archives."
(let ((v (ignore-errors
(file-symlink-p . tramp-handle-file-symlink-p)
(file-system-info . tramp-crypt-handle-file-system-info)
;; `file-truename' performed by default handler.
+ (file-user-uid . tramp-handle-file-user-uid)
(file-writable-p . tramp-crypt-handle-file-writable-p)
(find-backup-file-name . tramp-handle-find-backup-file-name)
;; `get-file-buffer' performed by default handler.
(file-symlink-p . tramp-handle-file-symlink-p)
(file-system-info . tramp-gvfs-handle-file-system-info)
(file-truename . tramp-handle-file-truename)
+ (file-user-uid . tramp-handle-file-user-uid)
(file-writable-p . tramp-handle-file-writable-p)
(find-backup-file-name . tramp-handle-find-backup-file-name)
;; `get-file-buffer' performed by default handler.
(file-symlink-p . tramp-handle-file-symlink-p)
(file-system-info . tramp-rclone-handle-file-system-info)
(file-truename . tramp-handle-file-truename)
+ (file-user-uid . tramp-handle-file-user-uid)
(file-writable-p . tramp-handle-file-writable-p)
(find-backup-file-name . tramp-handle-find-backup-file-name)
;; `get-file-buffer' performed by default handler.
(file-symlink-p . tramp-handle-file-symlink-p)
(file-system-info . tramp-sh-handle-file-system-info)
(file-truename . tramp-sh-handle-file-truename)
+ (file-user-uid . tramp-handle-file-user-uid)
(file-writable-p . tramp-sh-handle-file-writable-p)
(find-backup-file-name . tramp-handle-find-backup-file-name)
;; `get-file-buffer' performed by default handler.
(file-symlink-p . tramp-handle-file-symlink-p)
(file-system-info . tramp-smb-handle-file-system-info)
(file-truename . tramp-handle-file-truename)
+ (file-user-uid . tramp-handle-file-user-uid)
(file-writable-p . tramp-smb-handle-file-writable-p)
(find-backup-file-name . tramp-handle-find-backup-file-name)
;; `get-file-buffer' performed by default handler.
(file-symlink-p . tramp-handle-file-symlink-p)
(file-system-info . tramp-sshfs-handle-file-system-info)
(file-truename . tramp-handle-file-truename)
+ (file-user-uid . tramp-handle-file-user-uid)
(file-writable-p . tramp-sshfs-handle-file-writable-p)
(find-backup-file-name . tramp-handle-find-backup-file-name)
;; `get-file-buffer' performed by default handler.
(file-symlink-p . tramp-handle-file-symlink-p)
(file-system-info . tramp-sudoedit-handle-file-system-info)
(file-truename . tramp-sudoedit-handle-file-truename)
+ (file-user-uid . tramp-handle-file-user-uid)
(file-writable-p . tramp-sudoedit-handle-file-writable-p)
(find-backup-file-name . tramp-handle-find-backup-file-name)
;; `get-file-buffer' performed by default handler.
'(exec-path make-nearby-temp-file make-process process-file
shell-command start-file-process temporary-file-directory
;; Emacs 29+ only.
- list-system-processes memory-info process-attributes))
+ list-system-processes memory-info process-attributes
+ ;; Emacs 30+ only.
+ file-user-uid))
default-directory)
;; PROC.
((member operation '(file-notify-rm-watch file-notify-valid-p))
vec (concat "~" (substring filename (match-beginning 1))))
(tramp-make-tramp-file-name (tramp-dissect-file-name filename)))))
+(defun tramp-handle-file-user-uid ()
+ "Like `user-uid' for Tramp files."
+ (let ((v (tramp-dissect-file-name default-directory)))
+ (or (tramp-get-remote-uid v 'integer)
+ ;; Some handlers for `tramp-get-remote-uid' return nil if they
+ ;; can't get the UID; always return -1 in this case for
+ ;; consistency.
+ -1)))
+
(defun tramp-handle-access-file (filename string)
"Like `access-file' for Tramp files."
(setq filename (file-truename filename))
action))
(user-error "Shell command in progress"))))
+(defun file-user-uid ()
+ "Return the connection-local effective uid.
+This is similar to `user-uid', but may invoke a file name handler
+based on `default-directory'. See Info node `(elisp)Magic File
+Names'.
+
+If a file name handler is unable to retrieve the effective uid,
+this function will instead return -1."
+ (if-let ((handler (find-file-name-handler default-directory 'file-user-uid)))
+ (funcall handler 'file-user-uid)
+ (user-uid)))
+
(defun max-mini-window-lines (&optional frame)
"Compute maximum number of lines for echo area in FRAME.
As defined by `max-mini-window-height'. FRAME defaults to the
(format "cd %s" ert-remote-temporary-file-directory))
(eshell-match-command-output "echo $PATH" (regexp-quote remote-path)))))
+(ert-deftest esh-var-test/uid-var ()
+ "Test that $UID is equivalent to (user-uid) for local directories."
+ (eshell-command-result-equal "echo $UID" (user-uid)))
+
(ert-deftest esh-var-test/last-status-var-lisp-command ()
"Test using the \"last exit status\" ($?) variable with a Lisp command"
(with-temp-eshell