diff options
| author | Michael Albinus | 2025-04-01 15:24:44 +0200 |
|---|---|---|
| committer | Michael Albinus | 2025-04-01 15:24:44 +0200 |
| commit | 3f9ac99fc7e024678dff1ac3ff38e617ef2606fe (patch) | |
| tree | 10522887786bdf3081c62679d7ab190ef3425310 | |
| parent | 6cac92928a99a2cf33aeeeddf295cf981750391c (diff) | |
| download | emacs-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.el | 17 | ||||
| -rw-r--r-- | lisp/net/tramp-gvfs.el | 5 | ||||
| -rw-r--r-- | lisp/net/tramp-sh.el | 23 | ||||
| -rw-r--r-- | lisp/net/tramp-sudoedit.el | 24 | ||||
| -rw-r--r-- | lisp/net/tramp.el | 31 | ||||
| -rw-r--r-- | test/lisp/net/tramp-tests.el | 4 |
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. |
| 3513 | This is relevant for read, write, and execute permissions. On some file | 3513 | This is relevant for read, write, and execute permissions. On some file |
| 3514 | systems using NFS4_ACL, the permission string as returned from `stat' or | 3514 | systems 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. |
| 6429 | Return t if according to the cache access type ACCESS is known to | 6433 | Return t if according to the cache access type ACCESS is known to be |
| 6430 | be granted." | 6434 | granted, if `tramp-use-file-attributes' mandates this. If FORCE is |
| 6435 | non-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)) |