aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael Albinus2025-04-01 15:24:44 +0200
committerMichael Albinus2025-04-01 15:24:44 +0200
commit3f9ac99fc7e024678dff1ac3ff38e617ef2606fe (patch)
tree10522887786bdf3081c62679d7ab190ef3425310
parent6cac92928a99a2cf33aeeeddf295cf981750391c (diff)
downloademacs-3f9ac99fc7e024678dff1ac3ff38e617ef2606fe.tar.gz
emacs-3f9ac99fc7e024678dff1ac3ff38e617ef2606fe.zip
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.
-rw-r--r--lisp/net/tramp-adb.el17
-rw-r--r--lisp/net/tramp-gvfs.el5
-rw-r--r--lisp/net/tramp-sh.el23
-rw-r--r--lisp/net/tramp-sudoedit.el24
-rw-r--r--lisp/net/tramp.el31
-rw-r--r--test/lisp/net/tramp-tests.el4
6 files changed, 54 insertions, 50 deletions
diff --git a/lisp/net/tramp-adb.el b/lisp/net/tramp-adb.el
index 1ecabd8165f..dee6b7899e9 100644
--- a/lisp/net/tramp-adb.el
+++ b/lisp/net/tramp-adb.el
@@ -480,11 +480,11 @@ Emacs dired can't find files."
480 (with-tramp-file-property v localname "file-executable-p" 480 (with-tramp-file-property v localname "file-executable-p"
481 ;; Examine `file-attributes' cache to see if request can be 481 ;; Examine `file-attributes' cache to see if request can be
482 ;; satisfied without remote operation. 482 ;; satisfied without remote operation.
483 (if (tramp-use-file-attributes v) 483 (or (tramp-check-cached-permissions v ?x)
484 (or (tramp-check-cached-permissions v ?x) 484 (tramp-check-cached-permissions v ?s)
485 (tramp-check-cached-permissions v ?s)) 485 (tramp-check-cached-permissions v ?t)
486 (tramp-adb-send-command-and-check 486 (tramp-adb-send-command-and-check
487 v (format "test -x %s" (tramp-shell-quote-argument localname))))))) 487 v (format "test -x %s" (tramp-shell-quote-argument localname)))))))
488 488
489(defun tramp-adb-handle-file-exists-p (filename) 489(defun tramp-adb-handle-file-exists-p (filename)
490 "Like `file-exists-p' for Tramp files." 490 "Like `file-exists-p' for Tramp files."
@@ -498,10 +498,9 @@ Emacs dired can't find files."
498 (with-tramp-file-property v localname "file-readable-p" 498 (with-tramp-file-property v localname "file-readable-p"
499 ;; Examine `file-attributes' cache to see if request can be 499 ;; Examine `file-attributes' cache to see if request can be
500 ;; satisfied without remote operation. 500 ;; satisfied without remote operation.
501 (if (tramp-use-file-attributes v) 501 (or (tramp-handle-file-readable-p filename)
502 (tramp-handle-file-readable-p filename) 502 (tramp-adb-send-command-and-check
503 (tramp-adb-send-command-and-check 503 v (format "test -r %s" (tramp-shell-quote-argument localname)))))))
504 v (format "test -r %s" (tramp-shell-quote-argument localname)))))))
505 504
506(defun tramp-adb-handle-file-writable-p (filename) 505(defun tramp-adb-handle-file-writable-p (filename)
507 "Like `file-writable-p' for Tramp files." 506 "Like `file-writable-p' for Tramp files."
diff --git a/lisp/net/tramp-gvfs.el b/lisp/net/tramp-gvfs.el
index 3df69d79fce..9530aa3733a 100644
--- a/lisp/net/tramp-gvfs.el
+++ b/lisp/net/tramp-gvfs.el
@@ -1467,8 +1467,9 @@ If FILE-SYSTEM is non-nil, return file system attributes."
1467 "Like `file-executable-p' for Tramp files." 1467 "Like `file-executable-p' for Tramp files."
1468 (with-parsed-tramp-file-name (expand-file-name filename) nil 1468 (with-parsed-tramp-file-name (expand-file-name filename) nil
1469 (with-tramp-file-property v localname "file-executable-p" 1469 (with-tramp-file-property v localname "file-executable-p"
1470 (or (tramp-check-cached-permissions v ?x) 1470 (or (tramp-check-cached-permissions v ?x 'force)
1471 (tramp-check-cached-permissions v ?s))))) 1471 (tramp-check-cached-permissions v ?s 'force)
1472 (tramp-check-cached-permissions v ?t 'force)))))
1472 1473
1473(defun tramp-gvfs-handle-file-name-all-completions (filename directory) 1474(defun tramp-gvfs-handle-file-name-all-completions (filename directory)
1474 "Like `file-name-all-completions' for Tramp files." 1475 "Like `file-name-all-completions' for Tramp files."
diff --git a/lisp/net/tramp-sh.el b/lisp/net/tramp-sh.el
index ef4ddee8a53..4b770e95038 100644
--- a/lisp/net/tramp-sh.el
+++ b/lisp/net/tramp-sh.el
@@ -1783,10 +1783,10 @@ ID-FORMAT valid values are `string' and `integer'."
1783 (with-tramp-file-property v localname "file-executable-p" 1783 (with-tramp-file-property v localname "file-executable-p"
1784 ;; Examine `file-attributes' cache to see if request can be 1784 ;; Examine `file-attributes' cache to see if request can be
1785 ;; satisfied without remote operation. 1785 ;; satisfied without remote operation.
1786 (if (tramp-use-file-attributes v) 1786 (or (tramp-check-cached-permissions v ?x)
1787 (or (tramp-check-cached-permissions v ?x) 1787 (tramp-check-cached-permissions v ?s)
1788 (tramp-check-cached-permissions v ?s)) 1788 (tramp-check-cached-permissions v ?t)
1789 (tramp-run-test v "-x" localname))))) 1789 (tramp-run-test v "-x" localname)))))
1790 1790
1791(defun tramp-sh-handle-file-readable-p (filename) 1791(defun tramp-sh-handle-file-readable-p (filename)
1792 "Like `file-readable-p' for Tramp files." 1792 "Like `file-readable-p' for Tramp files."
@@ -1794,9 +1794,8 @@ ID-FORMAT valid values are `string' and `integer'."
1794 (with-tramp-file-property v localname "file-readable-p" 1794 (with-tramp-file-property v localname "file-readable-p"
1795 ;; Examine `file-attributes' cache to see if request can be 1795 ;; Examine `file-attributes' cache to see if request can be
1796 ;; satisfied without remote operation. 1796 ;; satisfied without remote operation.
1797 (if (tramp-use-file-attributes v) 1797 (or (tramp-handle-file-readable-p filename)
1798 (tramp-handle-file-readable-p filename) 1798 (tramp-run-test v "-r" localname)))))
1799 (tramp-run-test v "-r" localname)))))
1800 1799
1801;; Functions implemented using the basic functions above. 1800;; Functions implemented using the basic functions above.
1802 1801
@@ -1826,13 +1825,11 @@ ID-FORMAT valid values are `string' and `integer'."
1826 (if (file-exists-p filename) 1825 (if (file-exists-p filename)
1827 ;; Examine `file-attributes' cache to see if request can be 1826 ;; Examine `file-attributes' cache to see if request can be
1828 ;; satisfied without remote operation. 1827 ;; satisfied without remote operation.
1829 (if (tramp-use-file-attributes v) 1828 (or (tramp-check-cached-permissions v ?w)
1830 (tramp-check-cached-permissions v ?w) 1829 (tramp-run-test v "-w" localname))
1831 (tramp-run-test v "-w" localname))
1832 ;; If file doesn't exist, check if directory is writable. 1830 ;; If file doesn't exist, check if directory is writable.
1833 (and 1831 (and (file-directory-p (file-name-directory filename))
1834 (file-directory-p (file-name-directory filename)) 1832 (file-writable-p (file-name-directory filename)))))))
1835 (file-writable-p (file-name-directory filename)))))))
1836 1833
1837(defun tramp-sh-handle-file-ownership-preserved-p (filename &optional group) 1834(defun tramp-sh-handle-file-ownership-preserved-p (filename &optional group)
1838 "Like `file-ownership-preserved-p' for Tramp files." 1835 "Like `file-ownership-preserved-p' for Tramp files."
diff --git a/lisp/net/tramp-sudoedit.el b/lisp/net/tramp-sudoedit.el
index ff01eac5b93..59b4ea46b8c 100644
--- a/lisp/net/tramp-sudoedit.el
+++ b/lisp/net/tramp-sudoedit.el
@@ -479,11 +479,11 @@ the result will be a local, non-Tramp, file name."
479 (with-tramp-file-property v localname "file-executable-p" 479 (with-tramp-file-property v localname "file-executable-p"
480 ;; Examine `file-attributes' cache to see if request can be 480 ;; Examine `file-attributes' cache to see if request can be
481 ;; satisfied without remote operation. 481 ;; satisfied without remote operation.
482 (if (tramp-use-file-attributes v) 482 (or (tramp-check-cached-permissions v ?x)
483 (or (tramp-check-cached-permissions v ?x) 483 (tramp-check-cached-permissions v ?s)
484 (tramp-check-cached-permissions v ?s)) 484 (tramp-check-cached-permissions v ?t)
485 (tramp-sudoedit-send-command 485 (tramp-sudoedit-send-command
486 v "test" "-x" (file-name-unquote localname)))))) 486 v "test" "-x" (file-name-unquote localname))))))
487 487
488(defun tramp-sudoedit-handle-file-exists-p (filename) 488(defun tramp-sudoedit-handle-file-exists-p (filename)
489 "Like `file-exists-p' for Tramp files." 489 "Like `file-exists-p' for Tramp files."
@@ -519,10 +519,9 @@ the result will be a local, non-Tramp, file name."
519 (with-tramp-file-property v localname "file-readable-p" 519 (with-tramp-file-property v localname "file-readable-p"
520 ;; Examine `file-attributes' cache to see if request can be 520 ;; Examine `file-attributes' cache to see if request can be
521 ;; satisfied without remote operation. 521 ;; satisfied without remote operation.
522 (if (tramp-use-file-attributes v) 522 (or (tramp-handle-file-readable-p filename)
523 (tramp-handle-file-readable-p filename) 523 (tramp-sudoedit-send-command
524 (tramp-sudoedit-send-command 524 v "test" "-r" (file-name-unquote localname))))))
525 v "test" "-r" (file-name-unquote localname))))))
526 525
527(defun tramp-sudoedit-handle-set-file-modes (filename mode &optional flag) 526(defun tramp-sudoedit-handle-set-file-modes (filename mode &optional flag)
528 "Like `set-file-modes' for Tramp files." 527 "Like `set-file-modes' for Tramp files."
@@ -604,10 +603,9 @@ the result will be a local, non-Tramp, file name."
604 (if (file-exists-p filename) 603 (if (file-exists-p filename)
605 ;; Examine `file-attributes' cache to see if request can be 604 ;; Examine `file-attributes' cache to see if request can be
606 ;; satisfied without remote operation. 605 ;; satisfied without remote operation.
607 (if (tramp-use-file-attributes v) 606 (or (tramp-check-cached-permissions v ?w)
608 (tramp-check-cached-permissions v ?w) 607 (tramp-sudoedit-send-command
609 (tramp-sudoedit-send-command 608 v "test" "-w" (file-name-unquote localname)))
610 v "test" "-w" (file-name-unquote localname)))
611 ;; If file doesn't exist, check if directory is writable. 609 ;; If file doesn't exist, check if directory is writable.
612 (and 610 (and
613 (file-directory-p (file-name-directory filename)) 611 (file-directory-p (file-name-directory filename))
diff --git a/lisp/net/tramp.el b/lisp/net/tramp.el
index ec8835c13f0..6c1a4ae7127 100644
--- a/lisp/net/tramp.el
+++ b/lisp/net/tramp.el
@@ -3509,7 +3509,7 @@ BODY is the backend specific code."
3509 nil))) 3509 nil)))
3510 3510
3511(defcustom tramp-use-file-attributes t 3511(defcustom tramp-use-file-attributes t
3512 "Whether to use \"file-attributes\" file property for check. 3512 "Whether to use \"file-attributes\" connection property for check.
3513This is relevant for read, write, and execute permissions. On some file 3513This is relevant for read, write, and execute permissions. On some file
3514systems using NFS4_ACL, the permission string as returned from `stat' or 3514systems using NFS4_ACL, the permission string as returned from `stat' or
3515`ls', is not sufficient to provide more fine-grained information. 3515`ls', is not sufficient to provide more fine-grained information.
@@ -4331,13 +4331,12 @@ Let-bind it when necessary.")
4331 "Like `file-readable-p' for Tramp files." 4331 "Like `file-readable-p' for Tramp files."
4332 (with-parsed-tramp-file-name (expand-file-name filename) nil 4332 (with-parsed-tramp-file-name (expand-file-name filename) nil
4333 (with-tramp-file-property v localname "file-readable-p" 4333 (with-tramp-file-property v localname "file-readable-p"
4334 (or (tramp-check-cached-permissions v ?r) 4334 (or (tramp-check-cached-permissions v ?r 'force)
4335 ;; `tramp-check-cached-permissions' doesn't handle symbolic 4335 ;; `tramp-check-cached-permissions' doesn't handle symbolic
4336 ;; links. 4336 ;; links.
4337 (and-let* ((symlink (file-symlink-p filename)) 4337 (and-let* ((symlink (file-symlink-p filename))
4338 ((stringp symlink)) 4338 ((stringp symlink))
4339 ((file-readable-p 4339 ((file-readable-p (file-truename filename)))))))))
4340 (concat (file-remote-p filename) symlink)))))))))
4341 4340
4342(defun tramp-handle-file-regular-p (filename) 4341(defun tramp-handle-file-regular-p (filename)
4343 "Like `file-regular-p' for Tramp files." 4342 "Like `file-regular-p' for Tramp files."
@@ -4431,7 +4430,12 @@ existing) are returned."
4431 (with-parsed-tramp-file-name (expand-file-name filename) nil 4430 (with-parsed-tramp-file-name (expand-file-name filename) nil
4432 (with-tramp-file-property v localname "file-writable-p" 4431 (with-tramp-file-property v localname "file-writable-p"
4433 (if (file-exists-p filename) 4432 (if (file-exists-p filename)
4434 (tramp-check-cached-permissions v ?w) 4433 (or (tramp-check-cached-permissions v ?w 'force)
4434 ;; `tramp-check-cached-permissions' doesn't handle
4435 ;; symbolic links.
4436 (and-let* ((symlink (file-symlink-p filename))
4437 ((stringp symlink))
4438 ((file-writable-p (file-truename filename))))))
4435 ;; If file doesn't exist, check if directory is writable. 4439 ;; If file doesn't exist, check if directory is writable.
4436 (and (file-directory-p (file-name-directory filename)) 4440 (and (file-directory-p (file-name-directory filename))
4437 (file-writable-p (file-name-directory filename))))))) 4441 (file-writable-p (file-name-directory filename)))))))
@@ -6424,23 +6428,24 @@ VEC is used for tracing."
6424 (when vec (tramp-message vec 7 "locale %s" (or locale "C"))) 6428 (when vec (tramp-message vec 7 "locale %s" (or locale "C")))
6425 (or locale "C")))) 6429 (or locale "C"))))
6426 6430
6427(defun tramp-check-cached-permissions (vec access) 6431(defun tramp-check-cached-permissions (vec access &optional force)
6428 "Check `file-attributes' caches for VEC. 6432 "Check `file-attributes' caches for VEC.
6429Return t if according to the cache access type ACCESS is known to 6433Return t if according to the cache access type ACCESS is known to be
6430be granted." 6434granted, if `tramp-use-file-attributes' mandates this. If FORCE is
6435non-nil, use connection property \"file-attributes\" mandatory."
6431 (when-let* ((offset (cond 6436 (when-let* ((offset (cond
6432 ((eq ?r access) 1) 6437 ((eq ?r access) 1)
6433 ((eq ?w access) 2) 6438 ((eq ?w access) 2)
6434 ((eq ?x access) 3) 6439 ((eq ?x access) 3)
6435 ((eq ?s access) 3))) 6440 ((eq ?s access) 3)
6441 ((eq ?t access) 3)))
6442 ((or force (tramp-use-file-attributes vec)))
6436 (file-attr (file-attributes (tramp-make-tramp-file-name vec))) 6443 (file-attr (file-attributes (tramp-make-tramp-file-name vec)))
6444 ;; Not a symlink.
6445 ((not (stringp (file-attribute-type file-attr))))
6437 (remote-uid (tramp-get-remote-uid vec 'integer)) 6446 (remote-uid (tramp-get-remote-uid vec 'integer))
6438 (remote-gid (tramp-get-remote-gid vec 'integer))) 6447 (remote-gid (tramp-get-remote-gid vec 'integer)))
6439 (or 6448 (or
6440 ;; Not a symlink.
6441 (eq t (file-attribute-type file-attr))
6442 (null (file-attribute-type file-attr)))
6443 (or
6444 ;; World accessible. 6449 ;; World accessible.
6445 (eq access (aref (file-attribute-modes file-attr) (+ offset 6))) 6450 (eq access (aref (file-attribute-modes file-attr) (+ offset 6)))
6446 ;; User accessible and owned by user. 6451 ;; User accessible and owned by user.
diff --git a/test/lisp/net/tramp-tests.el b/test/lisp/net/tramp-tests.el
index 605b26206c4..e22f1afc18b 100644
--- a/test/lisp/net/tramp-tests.el
+++ b/test/lisp/net/tramp-tests.el
@@ -4279,6 +4279,8 @@ This tests also `file-executable-p', `file-writable-p' and `set-file-modes'."
4279 (ignore-errors (delete-file tmp-name1)) 4279 (ignore-errors (delete-file tmp-name1))
4280 (ignore-errors (delete-file tmp-name2))))))) 4280 (ignore-errors (delete-file tmp-name2)))))))
4281 4281
4282(tramp--test-deftest-without-file-attributes tramp-test20-file-modes)
4283
4282;; Method "smb" could run into "NT_STATUS_REVISION_MISMATCH" error. 4284;; Method "smb" could run into "NT_STATUS_REVISION_MISMATCH" error.
4283(defmacro tramp--test-ignore-add-name-to-file-error (&rest body) 4285(defmacro tramp--test-ignore-add-name-to-file-error (&rest body)
4284 "Run BODY, ignoring \"error with add-name-to-file\" file error." 4286 "Run BODY, ignoring \"error with add-name-to-file\" file error."
@@ -4578,6 +4580,8 @@ This tests also `make-symbolic-link', `file-truename' and `add-name-to-file'."
4578 (should (string-equal (file-truename dir1) (expand-file-name dir1))) 4580 (should (string-equal (file-truename dir1) (expand-file-name dir1)))
4579 (should (string-equal (file-truename dir2) (expand-file-name dir2))))))) 4581 (should (string-equal (file-truename dir2) (expand-file-name dir2)))))))
4580 4582
4583(tramp--test-deftest-without-file-attributes tramp-test21-file-links)
4584
4581(ert-deftest tramp-test22-file-times () 4585(ert-deftest tramp-test22-file-times ()
4582 "Check `set-file-times' and `file-newer-than-file-p'." 4586 "Check `set-file-times' and `file-newer-than-file-p'."
4583 (skip-unless (tramp--test-enabled)) 4587 (skip-unless (tramp--test-enabled))