From: Michael Albinus Date: Tue, 1 Apr 2025 13:24:44 +0000 (+0200) Subject: Fix Tramp's file-attributes cache X-Git-Url: http://git.eshelyaron.com/gitweb/?a=commitdiff_plain;h=811f061f1930b2d650f7a6d5b897f889ffc779bd;p=emacs.git Fix Tramp's file-attributes cache * lisp/net/tramp-adb.el (tramp-adb-handle-file-executable-p): Check also for sticky bit. (tramp-adb-handle-file-readable-p): Simplify. * lisp/net/tramp-gvfs.el (tramp-gvfs-handle-file-executable-p): Check also for sticky bit. Force `file-attributes' check. * lisp/net/tramp-sh.el (tramp-sh-handle-file-executable-p): Check also for sticky bit. (tramp-sh-handle-file-readable-p) (tramp-sh-handle-file-writable-p): Simplify. * lisp/net/tramp-sudoedit.el (tramp-sudoedit-handle-file-executable-p): Check also for sticky bit. (tramp-sudoedit-handle-file-readable-p) (tramp-sudoedit-handle-file-writable-p): Simplify. * lisp/net/tramp.el (tramp-use-file-attributes): Fix docstring. (tramp-handle-file-readable-p, tramp-handle-file-writable-p): Force `file-attributes' check. Use `file-truename' for symbolic links. (tramp-check-cached-permissions): New optional argument FORCE. Fix symlink check. Check also for sticky bit. (Bug#77402) * test/lisp/net/tramp-tests.el (tramp-test20-file-modes-without-file-attributes) (tramp-test21-file-links-without-file-attributes): New tests. (cherry picked from commit 3f9ac99fc7e024678dff1ac3ff38e617ef2606fe) --- diff --git a/lisp/net/tramp-adb.el b/lisp/net/tramp-adb.el index e9f64060d82..883345506a1 100644 --- a/lisp/net/tramp-adb.el +++ b/lisp/net/tramp-adb.el @@ -484,11 +484,11 @@ Emacs dired can't find files." (with-tramp-file-property v localname "file-executable-p" ;; Examine `file-attributes' cache to see if request can be ;; satisfied without remote operation. - (if (tramp-use-file-attributes v) - (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))))))) + (or (tramp-check-cached-permissions v ?x) + (tramp-check-cached-permissions v ?s) + (tramp-check-cached-permissions v ?t) + (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." @@ -502,10 +502,9 @@ Emacs dired can't find files." (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-use-file-attributes v) - (tramp-handle-file-readable-p filename) - (tramp-adb-send-command-and-check - v (format "test -r %s" (tramp-shell-quote-argument localname))))))) + (or (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." diff --git a/lisp/net/tramp-gvfs.el b/lisp/net/tramp-gvfs.el index 0ea9f4bb66c..248ffb96822 100644 --- a/lisp/net/tramp-gvfs.el +++ b/lisp/net/tramp-gvfs.el @@ -1469,8 +1469,9 @@ If FILE-SYSTEM is non-nil, return file system attributes." "Like `file-executable-p' for Tramp files." (with-parsed-tramp-file-name (expand-file-name filename) nil (with-tramp-file-property v localname "file-executable-p" - (or (tramp-check-cached-permissions v ?x) - (tramp-check-cached-permissions v ?s))))) + (or (tramp-check-cached-permissions v ?x 'force) + (tramp-check-cached-permissions v ?s 'force) + (tramp-check-cached-permissions v ?t 'force))))) (defun tramp-gvfs-handle-file-name-all-completions (filename directory) "Like `file-name-all-completions' for Tramp files." diff --git a/lisp/net/tramp-sh.el b/lisp/net/tramp-sh.el index 916a2e698d5..ab3af548c53 100644 --- a/lisp/net/tramp-sh.el +++ b/lisp/net/tramp-sh.el @@ -1789,10 +1789,10 @@ ID-FORMAT valid values are `string' and `integer'." (with-tramp-file-property v localname "file-executable-p" ;; Examine `file-attributes' cache to see if request can be ;; satisfied without remote operation. - (if (tramp-use-file-attributes v) - (or (tramp-check-cached-permissions v ?x) - (tramp-check-cached-permissions v ?s)) - (tramp-run-test v "-x" localname))))) + (or (tramp-check-cached-permissions v ?x) + (tramp-check-cached-permissions v ?s) + (tramp-check-cached-permissions v ?t) + (tramp-run-test v "-x" localname))))) (defun tramp-sh-handle-file-readable-p (filename) "Like `file-readable-p' for Tramp files." @@ -1800,9 +1800,8 @@ ID-FORMAT valid values are `string' and `integer'." (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-use-file-attributes v) - (tramp-handle-file-readable-p filename) - (tramp-run-test v "-r" localname))))) + (or (tramp-handle-file-readable-p filename) + (tramp-run-test v "-r" localname))))) ;; Functions implemented using the basic functions above. @@ -1832,13 +1831,11 @@ ID-FORMAT valid values are `string' and `integer'." (if (file-exists-p filename) ;; Examine `file-attributes' cache to see if request can be ;; satisfied without remote operation. - (if (tramp-use-file-attributes v) - (tramp-check-cached-permissions v ?w) - (tramp-run-test v "-w" localname)) + (or (tramp-check-cached-permissions v ?w) + (tramp-run-test v "-w" 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))))))) + (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." diff --git a/lisp/net/tramp-sudoedit.el b/lisp/net/tramp-sudoedit.el index 9705272804a..d21970e21ad 100644 --- a/lisp/net/tramp-sudoedit.el +++ b/lisp/net/tramp-sudoedit.el @@ -481,11 +481,11 @@ the result will be a local, non-Tramp, file name." (with-tramp-file-property v localname "file-executable-p" ;; Examine `file-attributes' cache to see if request can be ;; satisfied without remote operation. - (if (tramp-use-file-attributes v) - (or (tramp-check-cached-permissions v ?x) - (tramp-check-cached-permissions v ?s)) - (tramp-sudoedit-send-command - v "test" "-x" (file-name-unquote localname)))))) + (or (tramp-check-cached-permissions v ?x) + (tramp-check-cached-permissions v ?s) + (tramp-check-cached-permissions v ?t) + (tramp-sudoedit-send-command + v "test" "-x" (file-name-unquote localname)))))) (defun tramp-sudoedit-handle-file-exists-p (filename) "Like `file-exists-p' for Tramp files." @@ -521,10 +521,9 @@ the result will be a local, non-Tramp, file name." (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-use-file-attributes v) - (tramp-handle-file-readable-p filename) - (tramp-sudoedit-send-command - v "test" "-r" (file-name-unquote localname)))))) + (or (tramp-handle-file-readable-p filename) + (tramp-sudoedit-send-command + v "test" "-r" (file-name-unquote localname)))))) (defun tramp-sudoedit-handle-set-file-modes (filename mode &optional flag) "Like `set-file-modes' for Tramp files." @@ -606,10 +605,9 @@ the result will be a local, non-Tramp, file name." (if (file-exists-p filename) ;; Examine `file-attributes' cache to see if request can be ;; satisfied without remote operation. - (if (tramp-use-file-attributes v) - (tramp-check-cached-permissions v ?w) - (tramp-sudoedit-send-command - v "test" "-w" (file-name-unquote localname))) + (or (tramp-check-cached-permissions v ?w) + (tramp-sudoedit-send-command + v "test" "-w" (file-name-unquote localname))) ;; If file doesn't exist, check if directory is writable. (and (file-directory-p (file-name-directory filename)) diff --git a/lisp/net/tramp.el b/lisp/net/tramp.el index efd4f3591bc..920a76ef8f2 100644 --- a/lisp/net/tramp.el +++ b/lisp/net/tramp.el @@ -3540,7 +3540,7 @@ BODY is the backend specific code." nil))) (defcustom tramp-use-file-attributes t - "Whether to use \"file-attributes\" file property for check. + "Whether to use \"file-attributes\" connection property for check. This is relevant for read, write, and execute permissions. On some file systems using NFS4_ACL, the permission string as returned from `stat' or `ls', is not sufficient to provide more fine-grained information. @@ -4363,13 +4363,12 @@ Let-bind it when necessary.") "Like `file-readable-p' for Tramp files." (with-parsed-tramp-file-name (expand-file-name filename) nil (with-tramp-file-property v localname "file-readable-p" - (or (tramp-check-cached-permissions v ?r) + (or (tramp-check-cached-permissions v ?r 'force) ;; `tramp-check-cached-permissions' doesn't handle symbolic ;; links. - (when-let ((symlink (file-symlink-p filename))) - (and (stringp symlink) - (file-readable-p - (concat (file-remote-p filename) symlink)))))))) + (and-let* ((symlink (file-symlink-p filename)) + ((stringp symlink)) + ((file-readable-p (file-truename filename))))))))) (defun tramp-handle-file-regular-p (filename) "Like `file-regular-p' for Tramp files." @@ -4463,7 +4462,12 @@ existing) are returned." (with-parsed-tramp-file-name (expand-file-name filename) nil (with-tramp-file-property v localname "file-writable-p" (if (file-exists-p filename) - (tramp-check-cached-permissions v ?w) + (or (tramp-check-cached-permissions v ?w 'force) + ;; `tramp-check-cached-permissions' doesn't handle + ;; symbolic links. + (and-let* ((symlink (file-symlink-p filename)) + ((stringp symlink)) + ((file-writable-p (file-truename filename)))))) ;; 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))))))) @@ -6466,22 +6470,23 @@ VEC is used for tracing." (when vec (tramp-message vec 7 "locale %s" (or locale "C"))) (or locale "C")))) -(defun tramp-check-cached-permissions (vec access) +(defun tramp-check-cached-permissions (vec access &optional force) "Check `file-attributes' caches for VEC. -Return t if according to the cache access type ACCESS is known to -be granted." - (when-let ((offset (cond - ((eq ?r access) 1) - ((eq ?w access) 2) - ((eq ?x access) 3) - ((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))) - (or - ;; Not a symlink. - (eq t (file-attribute-type file-attr)) - (null (file-attribute-type file-attr))) +Return t if according to the cache access type ACCESS is known to be +granted, if `tramp-use-file-attributes' mandates this. If FORCE is +non-nil, use connection property \"file-attributes\" mandatory." + (when-let* ((offset (cond + ((eq ?r access) 1) + ((eq ?w access) 2) + ((eq ?x access) 3) + ((eq ?s access) 3) + ((eq ?t access) 3))) + ((or force (tramp-use-file-attributes vec))) + (file-attr (file-attributes (tramp-make-tramp-file-name vec))) + ;; Not a symlink. + ((not (stringp (file-attribute-type file-attr)))) + (remote-uid (tramp-get-remote-uid vec 'integer)) + (remote-gid (tramp-get-remote-gid vec 'integer))) (or ;; World accessible. (eq access (aref (file-attribute-modes file-attr) (+ offset 6))) diff --git a/test/lisp/net/tramp-tests.el b/test/lisp/net/tramp-tests.el index 54f66c26537..4e8640d4303 100644 --- a/test/lisp/net/tramp-tests.el +++ b/test/lisp/net/tramp-tests.el @@ -4255,6 +4255,8 @@ This tests also `file-executable-p', `file-writable-p' and `set-file-modes'." (ignore-errors (delete-file tmp-name1)) (ignore-errors (delete-file tmp-name2))))))) +(tramp--test-deftest-without-file-attributes tramp-test20-file-modes) + ;; Method "smb" could run into "NT_STATUS_REVISION_MISMATCH" error. (defmacro tramp--test-ignore-add-name-to-file-error (&rest body) "Run BODY, ignoring \"error with add-name-to-file\" file error." @@ -4554,6 +4556,8 @@ This tests also `make-symbolic-link', `file-truename' and `add-name-to-file'." (should (string-equal (file-truename dir1) (expand-file-name dir1))) (should (string-equal (file-truename dir2) (expand-file-name dir2))))))) +(tramp--test-deftest-without-file-attributes tramp-test21-file-links) + (ert-deftest tramp-test22-file-times () "Check `set-file-times' and `file-newer-than-file-p'." (skip-unless (tramp--test-enabled))