(file-attributes . tramp-adb-handle-file-attributes)
(file-directory-p . tramp-handle-file-directory-p)
(file-equal-p . tramp-handle-file-equal-p)
- ;; FIXME: This is too sloppy.
- (file-executable-p . tramp-handle-file-exists-p)
+ (file-executable-p . tramp-adb-handle-file-executable-p)
(file-exists-p . tramp-handle-file-exists-p)
(file-in-directory-p . tramp-handle-file-in-directory-p)
(file-local-copy . tramp-adb-handle-file-local-copy)
(file-notify-rm-watch . tramp-handle-file-notify-rm-watch)
(file-notify-valid-p . tramp-handle-file-notify-valid-p)
(file-ownership-preserved-p . ignore)
- (file-readable-p . tramp-handle-file-exists-p)
+ (file-readable-p . tramp-adb-handle-file-readable-p)
(file-regular-p . tramp-handle-file-regular-p)
(file-remote-p . tramp-handle-file-remote-p)
(file-selinux-context . tramp-handle-file-selinux-context)
(set-file-modes tmpfile (logior (or (file-modes filename) 0) #o0400)))
tmpfile)))
+(defun tramp-adb-handle-file-executable-p (filename)
+ "Like `file-executable-p' for Tramp files."
+ (with-parsed-tramp-file-name filename nil
+ (with-tramp-file-property v localname "file-executable-p"
+ (tramp-adb-send-command-and-check
+ v (format "test -x %s" (tramp-shell-quote-argument localname))))))
+
+(defun tramp-adb-handle-file-readable-p (filename)
+ "Like `file-readable-p' for Tramp files."
+ (with-parsed-tramp-file-name filename nil
+ (with-tramp-file-property v localname "file-readable-p"
+ (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.
-But handle the case, if the \"test\" command is not available."
+ "Like `file-writable-p' for Tramp files."
(with-parsed-tramp-file-name filename nil
(with-tramp-file-property v localname "file-writable-p"
- (if (tramp-adb-find-test-command v)
- (if (file-exists-p filename)
- (tramp-adb-send-command-and-check
- v (format "test -w %s" (tramp-shell-quote-argument localname)))
- (and
- (file-directory-p (file-name-directory filename))
- (file-writable-p (file-name-directory filename))))
-
- ;; Missing "test" command on Android < 4.
- (let ((rw-path "/data/data"))
- (tramp-message
- v 5
- "Not implemented yet (assuming \"/data/data\" is writable): %s"
- localname)
- (and (>= (length localname) (length rw-path))
- (string= (substring localname 0 (length rw-path))
- rw-path)))))))
+ (if (file-exists-p filename)
+ (tramp-adb-send-command-and-check
+ v (format "test -w %s" (tramp-shell-quote-argument localname)))
+ (and
+ (file-directory-p (file-name-directory filename))
+ (file-writable-p (file-name-directory filename)))))))
(defun tramp-adb-handle-write-region
(start end filename &optional append visit lockname mustbenew)
(rename-file remote-tmpstderr stderr))))
;; Read initial output. Remove the first
;; line, which is the command echo.
- (while
- (progn
- (goto-char (point-min))
- (not (re-search-forward "[\n]" nil t)))
- (tramp-accept-process-output p 0))
- (delete-region (point-min) (point))
+ (unless (eq filter t)
+ (while
+ (progn
+ (goto-char (point-min))
+ (not (re-search-forward "[\n]" nil t)))
+ (tramp-accept-process-output p 0))
+ (delete-region (point-min) (point)))
;; Provide error buffer. This shows only
;; initial error messages; messages arriving
;; later on will be inserted when the
(let ((inhibit-read-only t)) (delete-region (point-min) (point-max)))
(zerop (apply #'tramp-call-process vec tramp-adb-program nil t nil args))))
-(defun tramp-adb-find-test-command (vec)
- "Check whether the ash has a builtin \"test\" command.
-This happens for Android >= 4.0."
- (with-tramp-connection-property vec "test"
- (tramp-adb-send-command-and-check vec "type test")))
-
;; Connection functions
(defun tramp-adb-send-command (vec command &optional neveropen nooutput)
(file-notify-rm-watch . tramp-handle-file-notify-rm-watch)
(file-notify-valid-p . tramp-handle-file-notify-valid-p)
(file-ownership-preserved-p . ignore)
- (file-readable-p . tramp-gvfs-handle-file-readable-p)
+ (file-readable-p . tramp-handle-file-readable-p)
(file-regular-p . tramp-handle-file-regular-p)
(file-remote-p . tramp-handle-file-remote-p)
(file-selinux-context . tramp-handle-file-selinux-context)
"Like `file-executable-p' for Tramp files."
(with-parsed-tramp-file-name filename nil
(with-tramp-file-property v localname "file-executable-p"
- (and (file-exists-p filename)
- (tramp-check-cached-permissions v ?x)))))
+ (tramp-check-cached-permissions v ?x))))
(defun tramp-gvfs-handle-file-name-all-completions (filename directory)
"Like `file-name-all-completions' for Tramp files."
(when string (tramp-message proc 10 "Rest string:\n%s" string))
(process-put proc 'rest-string string)))
-(defun tramp-gvfs-handle-file-readable-p (filename)
- "Like `file-readable-p' for Tramp files."
- (with-parsed-tramp-file-name filename nil
- (with-tramp-file-property v localname "file-readable-p"
- (and (file-exists-p filename)
- (or (tramp-check-cached-permissions v ?r)
- ;; `tramp-check-cached-permissions' doesn't handle
- ;; symbolic links.
- (and (stringp (file-symlink-p filename))
- (file-readable-p
- (concat
- (file-remote-p filename) (file-symlink-p filename))))
- ;; If the user is different from what we guess to be
- ;; the user, we don't know. Let's check, whether
- ;; access is restricted explicitly.
- (and (/= (tramp-get-remote-uid v 'integer)
- (tramp-compat-file-attribute-user-id
- (file-attributes filename 'integer)))
- (not
- (string-equal
- "FALSE"
- (cdr (assoc
- "access::can-read"
- (tramp-gvfs-get-file-attributes filename)))))))))))
-
(defun tramp-gvfs-handle-file-system-info (filename)
"Like `file-system-info' for Tramp files."
(setq filename (directory-file-name (expand-file-name filename)))
"Like `file-readable-p' for Tramp files."
(with-parsed-tramp-file-name filename nil
(with-tramp-file-property v localname "file-readable-p"
- ;; Examine `file-attributes' cache to see if request can be
- ;; satisfied without remote operation.
- (or (tramp-check-cached-permissions v ?r)
+ (or (tramp-handle-file-readable-p filename)
(tramp-run-test "-r" filename)))))
;; Functions implemented using the basic functions above.
"Like `file-readable-p' for Tramp files."
(with-parsed-tramp-file-name filename nil
(with-tramp-file-property v localname "file-readable-p"
- (tramp-sudoedit-send-command
- v "test" "-r" (tramp-compat-file-name-unquote localname)))))
+ (or (tramp-handle-file-readable-p filename)
+ (tramp-sudoedit-send-command
+ v "test" "-r" (tramp-compat-file-name-unquote localname))))))
(defun tramp-sudoedit-handle-set-file-modes (filename mode &optional flag)
"Like `set-file-modes' for Tramp files."
signal identifier to be raised, remaining arguments passed to
`tramp-message'. Finally, signal SIGNAL is raised with
FMT-STRING and ARGUMENTS."
- (let ((inhibit-message t)
- signal-hook-function)
+ (let (signal-hook-function)
(tramp-backtrace vec-or-proc)
(unless arguments
;; FMT-STRING could be just a file name, as in
;; `custom-initialize-*' functions provoke `void-variable' errors.
;; We don't want to see them in the backtrace.
(unless (eq error-symbol 'void-variable)
- (tramp-error
- (car tramp-current-connection) error-symbol
- (mapconcat (lambda (x) (format "%s" x)) data " "))))
+ (let ((inhibit-message t))
+ (tramp-error
+ (car tramp-current-connection) error-symbol
+ (mapconcat (lambda (x) (format "%s" x)) data " ")))))
(put #'tramp-signal-hook-function 'tramp-suppress-trace t)
(defun tramp-handle-access-file (filename string)
"Like `access-file' for Tramp files."
- (unless (file-readable-p (file-truename filename))
- (tramp-compat-file-missing
- (tramp-dissect-file-name filename)
- (format "%s: %s" string filename))))
+ (setq filename (file-truename filename))
+ (with-parsed-tramp-file-name filename v
+ (if (file-exists-p filename)
+ (unless
+ (funcall
+ (if (file-directory-p filename)
+ #'file-accessible-directory-p #'file-readable-p)
+ filename)
+ (tramp-error
+ v 'file-error (format "%s: Permission denied, %s" string filename)))
+ (tramp-compat-file-missing
+ v (format "%s: No such file or directory, %s" string filename)))))
(defun tramp-handle-add-name-to-file
(filename newname &optional ok-if-already-exists)
(tramp-compat-file-attribute-modification-time
(file-attributes file1))))))
+(defun tramp-handle-file-readable-p (filename)
+ "Like `file-readable-p' for Tramp files."
+ (with-parsed-tramp-file-name filename nil
+ (with-tramp-file-property v localname "file-readable-p"
+ (or (tramp-check-cached-permissions v ?r)
+ ;; `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))))))))
+
(defun tramp-handle-file-regular-p (filename)
"Like `file-regular-p' for Tramp files."
(and (file-exists-p filename)
:name name :buffer buffer
:command (append `(,login-program) login-args command)
:coding coding :noquery noquery :connection-type connection-type
- :filter filter :sentinel sentinel :stderr stderr))
+ :sentinel sentinel :stderr stderr))
+ ;; Set filter. Prior Emacs 29.1, it doesn't work reliable
+ ;; to provide it as `make-process' argument when filter is
+ ;; t. See Bug#51177.
+ (when filter
+ (set-process-filter p filter))
(tramp-message v 6 "%s" (string-join (process-command p) " "))
p))))))
(regexp-opt (directory-files tmp-name1))
(length (directory-files tmp-name1)))))))
- ;; Check error case.
+ ;; Check error cases.
+ (when (and (tramp--test-supports-file-modes-p)
+ ;; With "sshfs", directories with zero file
+ ;; modes are still "accessible".
+ (not (tramp--test-sshfs-p))
+ ;; A directory is always accessible for user "root".
+ (not (zerop (tramp-compat-file-attribute-user-id
+ (file-attributes tmp-name1)))))
+ (set-file-modes tmp-name1 0)
+ (with-temp-buffer
+ (should-error
+ (insert-directory tmp-name1 nil)
+ :type 'file-error))
+ (set-file-modes tmp-name1 #o777))
(delete-directory tmp-name1 'recursive)
(with-temp-buffer
(should-error
(tramp-get-remote-gid tramp-test-vec 'integer)))
(delete-file tmp-name1))
+ (when (and (tramp--test-supports-file-modes-p)
+ ;; A file is always accessible for user "root".
+ (not (zerop (tramp-compat-file-attribute-user-id
+ (file-attributes
+ tramp-test-temporary-file-directory)))))
+ (write-region "foo" nil tmp-name1)
+ (set-file-modes tmp-name1 0)
+ (should-error
+ (access-file tmp-name1 "error")
+ :type 'file-error)
+ (set-file-modes tmp-name1 #o777)
+ (delete-file tmp-name1))
(should-error
(access-file tmp-name1 "error")
:type tramp-file-missing)
+
;; `file-ownership-preserved-p' should return t for
;; non-existing files.
(when test-file-ownership-preserved-p