]> git.eshelyaron.com Git - emacs.git/commitdiff
Fix Tramp's file-attributes cache
authorMichael Albinus <michael.albinus@gmx.de>
Tue, 1 Apr 2025 13:24:44 +0000 (15:24 +0200)
committerEshel Yaron <me@eshelyaron.com>
Tue, 8 Apr 2025 05:35:37 +0000 (07:35 +0200)
* 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)

lisp/net/tramp-adb.el
lisp/net/tramp-gvfs.el
lisp/net/tramp-sh.el
lisp/net/tramp-sudoedit.el
lisp/net/tramp.el
test/lisp/net/tramp-tests.el

index e9f64060d8228cb62926d835911f9d49f5156743..883345506a1054085b30ba5c28961ef50693f0ef 100644 (file)
@@ -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."
index 0ea9f4bb66c45df85cf9b3106db0abcb89a59b2d..248ffb968226cd1289f0f9c556b2ea1f190fa605 100644 (file)
@@ -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."
index 916a2e698d5592fbf9c8a362d865b5078c55260b..ab3af548c535407beba2ae7aabde69d492a7f29d 100644 (file)
@@ -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."
index 9705272804a5da11fef81adfcc2732411614ac2d..d21970e21ad5306239ab62a93cefdcefe7f0e9df 100644 (file)
@@ -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))
index efd4f3591bcbd319bc02733658dd3013327e41e2..920a76ef8f215a62760f103bc78e965dfa5aff7b 100644 (file)
@@ -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)))
index 54f66c265373ffc16d187e3e373457a23d6e8372..4e8640d4303cb1f70fdbb7997060c742cb8ff268 100644 (file)
@@ -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))