]> code.delx.au - gnu-emacs/blobdiff - lisp/net/tramp-adb.el
Update copyright year to 2015
[gnu-emacs] / lisp / net / tramp-adb.el
index 14fb8575fffe829dc7cb4eaa08a8207e8e139b42..f5e201985f99a9390478543518cdb939aaa5b2ab 100644 (file)
@@ -1,8 +1,8 @@
 ;;; tramp-adb.el --- Functions for calling Android Debug Bridge from Tramp
 
-;; Copyright (C) 2011-2013 Free Software Foundation, Inc.
+;; Copyright (C) 2011-2015 Free Software Foundation, Inc.
 
-;; Author: Juergen Hoetzel <juergen@archlinux.org>
+;; Author: Jürgen Hötzel <juergen@archlinux.org>
 ;; Keywords: comm, processes
 ;; Package: tramp
 
@@ -34,9 +34,9 @@
 ;;; Code:
 
 (require 'tramp)
-(require 'time-date)
 
-(defvar dired-move-to-filename-regexp)
+;; Pacify byte-compiler.
+(defvar directory-sep-char)
 
 (defcustom tramp-adb-program "adb"
   "Name of the Android Debug Bridge program."
             (cons 'tramp-adb-file-name-p 'tramp-adb-file-name-handler))
 
 (defconst tramp-adb-file-name-handler-alist
-  '((directory-file-name . tramp-handle-directory-file-name)
+  '((access-file . ignore)
+    (add-name-to-file . tramp-adb-handle-copy-file)
+    ;; `byte-compiler-base-file-name' performed by default handler.
+    ;; `copy-directory' performed by default handler.
+    (copy-file . tramp-adb-handle-copy-file)
+    (delete-directory . tramp-adb-handle-delete-directory)
+    (delete-file . tramp-adb-handle-delete-file)
+    ;; `diff-latest-backup-file' performed by default handler.
+    (directory-file-name . tramp-handle-directory-file-name)
+    (directory-files . tramp-handle-directory-files)
+    (directory-files-and-attributes
+     . tramp-adb-handle-directory-files-and-attributes)
+    (dired-call-process . ignore)
+    (dired-compress-file . ignore)
     (dired-uncache . tramp-handle-dired-uncache)
+    (expand-file-name . tramp-adb-handle-expand-file-name)
+    (file-accessible-directory-p . tramp-handle-file-accessible-directory-p)
+    (file-acl . ignore)
+    (file-attributes . tramp-adb-handle-file-attributes)
+    (file-directory-p . tramp-adb-handle-file-directory-p)
+    ;; `file-equal-p' performed by default handler.
+    ;; FIXME: This is too sloppy.
+    (file-executable-p . tramp-handle-file-exists-p)
+    (file-exists-p . tramp-handle-file-exists-p)
+    ;; `file-in-directory-p' performed by default handler.
+    (file-local-copy . tramp-adb-handle-file-local-copy)
+    (file-modes . tramp-handle-file-modes)
+    (file-name-all-completions . tramp-adb-handle-file-name-all-completions)
     (file-name-as-directory . tramp-handle-file-name-as-directory)
     (file-name-completion . tramp-handle-file-name-completion)
-    (file-name-all-completions . tramp-adb-handle-file-name-all-completions)
-    (file-attributes . tramp-adb-handle-file-attributes)
     (file-name-directory . tramp-handle-file-name-directory)
     (file-name-nondirectory . tramp-handle-file-name-nondirectory)
-    (file-truename . tramp-adb-handle-file-truename)
+    ;; `file-name-sans-versions' performed by default handler.
     (file-newer-than-file-p . tramp-handle-file-newer-than-file-p)
-    (file-name-as-directory . tramp-handle-file-name-as-directory)
+    (file-notify-add-watch . tramp-handle-file-notify-add-watch)
+    (file-notify-rm-watch . tramp-handle-file-notify-rm-watch)
+    (file-ownership-preserved-p . ignore)
+    (file-readable-p . tramp-handle-file-exists-p)
     (file-regular-p . tramp-handle-file-regular-p)
     (file-remote-p . tramp-handle-file-remote-p)
-    (file-accessible-directory-p . tramp-handle-file-accessible-directory-p)
-    (file-directory-p . tramp-adb-handle-file-directory-p)
+    (file-selinux-context . ignore)
     (file-symlink-p . tramp-handle-file-symlink-p)
-    ;; FIXME: This is too sloppy.
-    (file-executable-p . tramp-handle-file-exists-p)
-    (file-exists-p . tramp-handle-file-exists-p)
-    (file-readable-p . tramp-handle-file-exists-p)
+    (file-truename . tramp-adb-handle-file-truename)
     (file-writable-p . tramp-adb-handle-file-writable-p)
-    (file-local-copy . tramp-adb-handle-file-local-copy)
-    (file-modes . tramp-handle-file-modes)
-    (expand-file-name . tramp-adb-handle-expand-file-name)
     (find-backup-file-name . tramp-handle-find-backup-file-name)
-    (directory-files . tramp-handle-directory-files)
-    (directory-files-and-attributes
-     . tramp-adb-handle-directory-files-and-attributes)
-    (make-directory . tramp-adb-handle-make-directory)
-    (delete-directory . tramp-adb-handle-delete-directory)
-    (delete-file . tramp-adb-handle-delete-file)
-    (load . tramp-handle-load)
-    (insert-directory . tramp-adb-handle-insert-directory)
+    ;; `find-file-noselect' performed by default handler.
+    ;; `get-file-buffer' performed by default handler.
+    (insert-directory . tramp-handle-insert-directory)
     (insert-file-contents . tramp-handle-insert-file-contents)
-    (substitute-in-file-name . tramp-handle-substitute-in-file-name)
-    (unhandled-file-name-directory . tramp-handle-unhandled-file-name-directory)
-    (vc-registered . ignore)   ;no  vc control files on Android devices
-    (write-region . tramp-adb-handle-write-region)
+    (load . tramp-handle-load)
+    (make-auto-save-file-name . tramp-handle-make-auto-save-file-name)
+    (make-directory . tramp-adb-handle-make-directory)
+    (make-directory-internal . ignore)
+    (make-symbolic-link . tramp-handle-make-symbolic-link)
+    (process-file . tramp-adb-handle-process-file)
+    (rename-file . tramp-adb-handle-rename-file)
+    (set-file-acl . ignore)
     (set-file-modes . tramp-adb-handle-set-file-modes)
+    (set-file-selinux-context . ignore)
     (set-file-times . tramp-adb-handle-set-file-times)
-    (copy-file . tramp-adb-handle-copy-file)
-    (rename-file . tramp-adb-handle-rename-file)
-    (process-file . tramp-adb-handle-process-file)
+    (set-visited-file-modtime . tramp-handle-set-visited-file-modtime)
     (shell-command . tramp-adb-handle-shell-command)
-    (start-file-process . tramp-adb-handle-start-file-process))
+    (start-file-process . tramp-adb-handle-start-file-process)
+    (substitute-in-file-name . tramp-handle-substitute-in-file-name)
+    (unhandled-file-name-directory . tramp-handle-unhandled-file-name-directory)
+    (vc-registered . ignore)
+    (verify-visited-file-modtime . tramp-handle-verify-visited-file-modtime)
+    (write-region . tramp-adb-handle-write-region))
   "Alist of handler functions for Tramp ADB method.")
 
 ;; It must be a `defsubst' in order to push the whole code into
@@ -151,7 +174,7 @@ pass to the OPERATION."
       (tramp-run-real-handler operation args))))
 
 ;;;###tramp-autoload
-(defun tramp-adb-parse-device-names (ignore)
+(defun tramp-adb-parse-device-names (_ignore)
   "Return a list of (nil host) tuples allowed to access."
   (with-timeout (10)
     (with-temp-buffer
@@ -162,7 +185,8 @@ pass to the OPERATION."
            result)
        (tramp-compat-set-process-query-on-exit-flag p nil)
        (while (eq 'run (process-status p))
-         (sleep-for 0.1))
+         (accept-process-output p 0.1))
+       (accept-process-output p 0.1)
        (goto-char (point-min))
        (while (search-forward-regexp "^\\(\\S-+\\)[[:space:]]+device$" nil t)
          (add-to-list 'result (list nil (match-string 1))))
@@ -201,85 +225,92 @@ pass to the OPERATION."
 
 ;; This is derived from `tramp-sh-handle-file-truename'.  Maybe the
 ;; code could be shared?
-(defun tramp-adb-handle-file-truename (filename &optional counter prev-dirs)
+(defun tramp-adb-handle-file-truename (filename)
   "Like `file-truename' for Tramp files."
-  (with-parsed-tramp-file-name (expand-file-name filename) nil
-    (with-tramp-file-property v localname "file-truename"
-      (let ((result nil))                      ; result steps in reverse order
-       (tramp-message v 4 "Finding true name for `%s'" filename)
-       (let* ((directory-sep-char ?/)
-              (steps (tramp-compat-split-string localname "/"))
-              (localnamedir (tramp-run-real-handler
-                             'file-name-as-directory (list localname)))
-              (is-dir (string= localname localnamedir))
-              (thisstep nil)
-              (numchase 0)
-              ;; Don't make the following value larger than
-              ;; necessary.  People expect an error message in a
-              ;; timely fashion when something is wrong; otherwise
-              ;; they might think that Emacs is hung.  Of course,
-              ;; correctness has to come first.
-              (numchase-limit 20)
-              symlink-target)
-         (while (and steps (< numchase numchase-limit))
-           (setq thisstep (pop steps))
-           (tramp-message
-            v 5 "Check %s"
-            (mapconcat 'identity
-                       (append '("") (reverse result) (list thisstep))
-                       "/"))
-           (setq symlink-target
-                 (nth 0 (file-attributes
-                         (tramp-make-tramp-file-name
-                          method user host
-                          (mapconcat 'identity
-                                     (append '("")
-                                             (reverse result)
-                                             (list thisstep))
-                                     "/")))))
-           (cond ((string= "." thisstep)
-                  (tramp-message v 5 "Ignoring step `.'"))
-                 ((string= ".." thisstep)
-                  (tramp-message v 5 "Processing step `..'")
-                  (pop result))
-                 ((stringp symlink-target)
-                  ;; It's a symlink, follow it.
-                  (tramp-message v 5 "Follow symlink to %s" symlink-target)
-                  (setq numchase (1+ numchase))
-                  (when (file-name-absolute-p symlink-target)
-                    (setq result nil))
-                  ;; If the symlink was absolute, we'll get a string
-                  ;; like "/user@host:/some/target"; extract the
-                  ;; "/some/target" part from it.
-                  (when (tramp-tramp-file-p symlink-target)
-                    (unless (tramp-equal-remote filename symlink-target)
-                      (tramp-error
-                       v 'file-error
-                       "Symlink target `%s' on wrong host" symlink-target))
-                    (setq symlink-target localname))
-                  (setq steps
-                        (append (tramp-compat-split-string
-                                 symlink-target "/")
-                                steps)))
-                 (t
-                  ;; It's a file.
-                  (setq result (cons thisstep result)))))
-         (when (>= numchase numchase-limit)
-           (tramp-error
-            v 'file-error
-            "Maximum number (%d) of symlinks exceeded" numchase-limit))
-         (setq result (reverse result))
-         ;; Combine list to form string.
-         (setq result
-               (if result
-                   (mapconcat 'identity (cons "" result) "/")
-                 "/"))
-         (when (and is-dir (or (string= "" result)
-                               (not (string= (substring result -1) "/"))))
-           (setq result (concat result "/"))))
-
-        (tramp-message v 4 "True name of `%s' is `%s'" filename result)
-        (tramp-make-tramp-file-name method user host result)))))
+  (format
+   "%s%s"
+   (with-parsed-tramp-file-name (expand-file-name filename) nil
+     (tramp-make-tramp-file-name
+      method user host
+      (with-tramp-file-property v localname "file-truename"
+       (let ((result nil))                     ; result steps in reverse order
+         (tramp-message v 4 "Finding true name for `%s'" filename)
+         (let* ((directory-sep-char ?/)
+                (steps (tramp-compat-split-string localname "/"))
+                (localnamedir (tramp-run-real-handler
+                               'file-name-as-directory (list localname)))
+                (is-dir (string= localname localnamedir))
+                (thisstep nil)
+                (numchase 0)
+                ;; Don't make the following value larger than
+                ;; necessary.  People expect an error message in a
+                ;; timely fashion when something is wrong; otherwise
+                ;; they might think that Emacs is hung.  Of course,
+                ;; correctness has to come first.
+                (numchase-limit 20)
+                symlink-target)
+           (while (and steps (< numchase numchase-limit))
+             (setq thisstep (pop steps))
+             (tramp-message
+              v 5 "Check %s"
+              (mapconcat 'identity
+                         (append '("") (reverse result) (list thisstep))
+                         "/"))
+             (setq symlink-target
+                   (nth 0 (file-attributes
+                           (tramp-make-tramp-file-name
+                            method user host
+                            (mapconcat 'identity
+                                       (append '("")
+                                               (reverse result)
+                                               (list thisstep))
+                                       "/")))))
+             (cond ((string= "." thisstep)
+                    (tramp-message v 5 "Ignoring step `.'"))
+                   ((string= ".." thisstep)
+                    (tramp-message v 5 "Processing step `..'")
+                    (pop result))
+                   ((stringp symlink-target)
+                    ;; It's a symlink, follow it.
+                    (tramp-message v 5 "Follow symlink to %s" symlink-target)
+                    (setq numchase (1+ numchase))
+                    (when (file-name-absolute-p symlink-target)
+                      (setq result nil))
+                    ;; If the symlink was absolute, we'll get a string
+                    ;; like "/user@host:/some/target"; extract the
+                    ;; "/some/target" part from it.
+                    (when (tramp-tramp-file-p symlink-target)
+                      (unless (tramp-equal-remote filename symlink-target)
+                        (tramp-error
+                         v 'file-error
+                         "Symlink target `%s' on wrong host" symlink-target))
+                      (setq symlink-target localname))
+                    (setq steps
+                          (append (tramp-compat-split-string
+                                   symlink-target "/")
+                                  steps)))
+                   (t
+                    ;; It's a file.
+                    (setq result (cons thisstep result)))))
+           (when (>= numchase numchase-limit)
+             (tramp-error
+              v 'file-error
+              "Maximum number (%d) of symlinks exceeded" numchase-limit))
+           (setq result (reverse result))
+           ;; Combine list to form string.
+           (setq result
+                 (if result
+                     (mapconcat 'identity (cons "" result) "/")
+                   "/"))
+           (when (and is-dir (or (string= "" result)
+                                 (not (string= (substring result -1) "/"))))
+             (setq result (concat result "/"))))
+
+         (tramp-message v 4 "True name of `%s' is `%s'" localname result)
+         result))))
+
+   ;; Preserve trailing "/".
+   (if (string-equal (file-name-nondirectory filename) "") "/" "")))
 
 (defun tramp-adb-handle-file-attributes (filename &optional id-format)
   "Like `file-attributes' for Tramp files."
@@ -288,13 +319,14 @@ pass to the OPERATION."
     (with-parsed-tramp-file-name filename nil
       (with-tramp-file-property
          v localname (format "file-attributes-%s" id-format)
-       (tramp-adb-barf-unless-okay
-        v (format "%s -d -l %s"
-                  (tramp-adb-get-ls-command v)
-                  (tramp-shell-quote-argument localname)) "")
-       (with-current-buffer (tramp-get-buffer v)
-         (tramp-adb-sh-fix-ls-output)
-         (cdar (tramp-do-parse-file-attributes-with-ls v id-format)))))))
+       (and
+        (tramp-adb-send-command-and-check
+         v (format "%s -d -l %s"
+                   (tramp-adb-get-ls-command v)
+                   (tramp-shell-quote-argument localname)))
+        (with-current-buffer (tramp-get-buffer v)
+          (tramp-adb-sh-fix-ls-output)
+          (cdar (tramp-do-parse-file-attributes-with-ls v id-format))))))))
 
 (defun tramp-do-parse-file-attributes-with-ls (vec &optional id-format)
   "Parse `file-attributes' for Tramp files using the ls(1) command."
@@ -341,11 +373,19 @@ pass to the OPERATION."
       (with-tramp-file-property
          v localname (format "directory-files-attributes-%s-%s-%s-%s"
                              full match id-format nosort)
-       (tramp-adb-barf-unless-okay
-        v (format "%s -a -l %s"
-                  (tramp-adb-get-ls-command v)
-                  (tramp-shell-quote-argument localname)) "")
        (with-current-buffer (tramp-get-buffer v)
+         (when (tramp-adb-send-command-and-check
+                v (format "%s -a -l %s"
+                          (tramp-adb-get-ls-command v)
+                          (tramp-shell-quote-argument localname)))
+           ;; We insert also filename/. and filename/.., because "ls" doesn't.
+           (narrow-to-region (point) (point))
+           (tramp-adb-send-command
+            v (format "%s -d -a -l %s %s"
+                      (tramp-adb-get-ls-command v)
+                      (concat (file-name-as-directory localname) ".")
+                      (concat (file-name-as-directory localname) "..")))
+           (widen))
          (tramp-adb-sh-fix-ls-output)
          (let ((result (tramp-do-parse-file-attributes-with-ls
                         v (or id-format 'integer))))
@@ -367,8 +407,7 @@ pass to the OPERATION."
 (defun tramp-adb-get-ls-command (vec)
   (with-tramp-connection-property vec "ls"
     (tramp-message vec 5 "Finding a suitable `ls' command")
-    (if        (zerop (tramp-adb-command-exit-status
-               vec "ls --color=never -al /dev/null"))
+    (if (tramp-adb-send-command-and-check vec "ls --color=never -al /dev/null")
        ;; On CyanogenMod based system BusyBox is used and "ls" output
        ;; coloring is enabled by default.  So we try to disable it
        ;; when possible.
@@ -382,9 +421,9 @@ Convert (\"-al\") to (\"-a\" \"-l\").  Remove arguments like \"--dired\"."
   (split-string
    (apply 'concat
          (mapcar (lambda (s)
-                   (replace-regexp-in-string
+                   (tramp-compat-replace-regexp-in-string
                     "\\(.\\)"  " -\\1"
-                    (replace-regexp-in-string "^-" "" s)))
+                    (tramp-compat-replace-regexp-in-string "^-" "" s)))
                  ;; FIXME: Warning about removed switches (long and non-dash).
                  (delq nil
                        (mapcar
@@ -392,35 +431,6 @@ Convert (\"-al\") to (\"-a\" \"-l\").  Remove arguments like \"--dired\"."
                           (and (not (string-match "\\(^--\\|^[^-]\\)" s)) s))
                         switches))))))
 
-(defun tramp-adb-handle-insert-directory
-  (filename switches &optional wildcard full-directory-p)
-  "Like `insert-directory' for Tramp files."
-  (when (stringp switches)
-    (setq switches (tramp-adb--gnu-switches-to-ash (split-string switches))))
-  (with-parsed-tramp-file-name (file-truename filename) nil
-    (with-current-buffer (tramp-get-buffer v)
-      (let ((name (tramp-shell-quote-argument (directory-file-name localname)))
-           (switch-d (member "-d" switches))
-           (switch-t (member "-t" switches))
-           (switches (mapconcat 'identity (remove "-t" switches) " ")))
-       (tramp-adb-barf-unless-okay
-        v (format "%s %s %s" (tramp-adb-get-ls-command v) switches name)
-        "Cannot insert directory listing: %s" filename)
-       (unless switch-d
-         ;; We insert also filename/. and filename/.., because "ls" doesn't.
-         (narrow-to-region (point) (point))
-         (ignore-errors
-           (tramp-adb-barf-unless-okay
-            v (format "%s -d %s %s %s"
-                      (tramp-adb-get-ls-command v)
-                      switches
-                      (concat (file-name-as-directory name) ".")
-                      (concat (file-name-as-directory name) ".."))
-            "Cannot insert directory listing: %s" filename))
-         (widen))
-       (tramp-adb-sh-fix-ls-output switch-t)))
-    (insert-buffer-substring (tramp-get-buffer v))))
-
 (defun tramp-adb-sh-fix-ls-output (&optional sort-by-time)
   "Insert dummy 0 in empty size columns.
 Androids \"ls\" command doesn't insert size column for directories:
@@ -448,9 +458,7 @@ Emacs dired can't find files."
       (insert "  " (mapconcat 'identity sorted-lines "\n  ")))
     ;; Add final newline.
     (goto-char (point-max))
-    (unless (= (point) (line-beginning-position))
-      (insert "\n"))))
-
+    (unless (bolp) (insert "\n"))))
 
 (defun tramp-adb-ls-output-time-less-p (a b)
   "Sort \"ls\" output by time, descending."
@@ -459,14 +467,14 @@ Emacs dired can't find files."
     (setq time-a (apply 'encode-time (parse-time-string (match-string 0 a))))
     (string-match tramp-adb-ls-date-regexp b)
     (setq time-b (apply 'encode-time (parse-time-string (match-string 0 b))))
-    (tramp-time-less-p time-b time-a)))
+    (time-less-p time-b time-a)))
 
 (defun tramp-adb-ls-output-name-less-p (a b)
   "Sort \"ls\" output by name, ascending."
   (let (posa posb)
-    (string-match dired-move-to-filename-regexp a)
+    (string-match directory-listing-before-filename-regexp a)
     (setq posa (match-end 0))
-    (string-match dired-move-to-filename-regexp b)
+    (string-match directory-listing-before-filename-regexp b)
     (setq posb (match-end 0))
     (string-lessp (substring a posa) (substring b posb))))
 
@@ -481,7 +489,8 @@ Emacs dired can't find files."
     (tramp-adb-barf-unless-okay
      v (format "mkdir %s" (tramp-shell-quote-argument localname))
      "Couldn't make directory %s" dir)
-    (tramp-flush-directory-property v (file-name-directory localname))))
+    (tramp-flush-file-property v (file-name-directory localname))
+    (tramp-flush-directory-property v localname)))
 
 (defun tramp-adb-handle-delete-directory (directory &optional recursive)
   "Like `delete-directory' for Tramp files."
@@ -495,7 +504,7 @@ Emacs dired can't find files."
               (tramp-shell-quote-argument localname))
      "Couldn't delete %s" directory)))
 
-(defun tramp-adb-handle-delete-file (filename &optional trash)
+(defun tramp-adb-handle-delete-file (filename &optional _trash)
   "Like `delete-file' for Tramp files."
   (setq filename (expand-file-name filename))
   (with-parsed-tramp-file-name filename nil
@@ -513,20 +522,22 @@ Emacs dired can't find files."
      (with-tramp-file-property v localname "file-name-all-completions"
        (save-match-data
         (tramp-adb-send-command
-         v (format "%s %s"
+         v (format "%s -a %s"
                    (tramp-adb-get-ls-command v)
                    (tramp-shell-quote-argument localname)))
         (mapcar
          (lambda (f)
-           (if (file-directory-p f)
+           (if (file-directory-p (expand-file-name f directory))
                (file-name-as-directory f)
              f))
          (with-current-buffer (tramp-get-buffer v)
-           (delq
-            nil
-            (mapcar
-             (lambda (l) (and (not (string-match  "^[[:space:]]*$" l)) l))
-             (split-string (buffer-string) "\n"))))))))))
+           (append
+            '("." "..")
+            (delq
+             nil
+             (mapcar
+              (lambda (l) (and (not (string-match  "^[[:space:]]*$" l)) l))
+              (split-string (buffer-string) "\n")))))))))))
 
 (defun tramp-adb-handle-file-local-copy (filename)
   "Like `file-local-copy' for Tramp files."
@@ -542,7 +553,10 @@ Emacs dired can't find files."
          (delete-file tmpfile)
          (tramp-error
           v 'file-error "Cannot make local copy of file `%s'" filename))
-       (set-file-modes tmpfile (file-modes filename)))
+       (set-file-modes
+        tmpfile
+        (logior (or (file-modes filename) 0)
+                (tramp-compat-octal-to-decimal "0400"))))
       tmpfile)))
 
 (defun tramp-adb-handle-file-writable-p (filename)
@@ -552,9 +566,8 @@ But handle the case, if the \"test\" command is not available."
     (with-tramp-file-property v localname "file-writable-p"
       (if (tramp-adb-find-test-command v)
          (if (file-exists-p filename)
-             (zerop
-              (tramp-adb-command-exit-status
-               v (format "test -w %s" (tramp-shell-quote-argument localname))))
+             (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))))
@@ -574,9 +587,6 @@ But handle the case, if the \"test\" command is not available."
   "Like `write-region' for Tramp files."
   (setq filename (expand-file-name filename))
   (with-parsed-tramp-file-name filename nil
-    (when append
-      (tramp-error
-       v 'file-error "Cannot append to file using Tramp (`%s')" filename))
     (when (and confirm (file-exists-p filename))
       (unless (y-or-n-p (format "File %s exists; overwrite anyway? "
                                filename))
@@ -587,16 +597,25 @@ But handle the case, if the \"test\" command is not available."
     (tramp-flush-file-property v localname)
     (let* ((curbuf (current-buffer))
           (tmpfile (tramp-compat-make-temp-file filename)))
+      (when (and append (file-exists-p filename))
+       (copy-file filename tmpfile 'ok)
+       (set-file-modes
+        tmpfile
+        (logior (or (file-modes tmpfile) 0)
+                (tramp-compat-octal-to-decimal "0600"))))
       (tramp-run-real-handler
        'write-region
        (list start end tmpfile append 'no-message lockname confirm))
       (with-tramp-progress-reporter
-         v 3 (format "Moving tmp file %s to %s" tmpfile filename)
+         v 3 (format "Moving tmp file `%s' to `%s'" tmpfile filename)
        (unwind-protect
            (when (tramp-adb-execute-adb-command v "push" tmpfile localname)
-             (tramp-error v 'file-error "Cannot write: `%s' filename"))
+             (tramp-error v 'file-error "Cannot write: `%s'" filename))
          (delete-file tmpfile)))
 
+      (when (or (eq visit t) (stringp visit))
+       (set-visited-file-modtime))
+
       (unless (equal curbuf (current-buffer))
        (tramp-error
         v 'file-error
@@ -606,9 +625,8 @@ But handle the case, if the \"test\" command is not available."
   "Like `set-file-modes' for Tramp files."
   (with-parsed-tramp-file-name filename nil
     (tramp-flush-file-property v localname)
-    (tramp-adb-barf-unless-okay
-     v (format "chmod %s %s" (tramp-compat-decimal-to-octal mode) localname)
-     "Error while changing file's mode %s" filename)))
+    (tramp-adb-send-command-and-check
+     v (format "chmod %s %s" (tramp-compat-decimal-to-octal mode) localname))))
 
 (defun tramp-adb-handle-set-file-times (filename &optional time)
   "Like `set-file-times' for Tramp files."
@@ -617,15 +635,15 @@ But handle the case, if the \"test\" command is not available."
     (let ((time (if (or (null time) (equal time '(0 0)))
                    (current-time)
                  time)))
-      (tramp-adb-command-exit-status
-       ;; use shell arithmetic because of Emacs integer size limit
+      (tramp-adb-send-command-and-check
+       ;; Use shell arithmetic because of Emacs integer size limit.
        v (format "touch -t $(( %d * 65536 + %d )) %s"
                 (car time) (cadr time)
                 (tramp-shell-quote-argument localname))))))
 
 (defun tramp-adb-handle-copy-file
   (filename newname &optional ok-if-already-exists keep-date
-           preserve-uid-gid preserve-extended-attributes)
+           _preserve-uid-gid _preserve-extended-attributes)
   "Like `copy-file' for Tramp files.
 PRESERVE-UID-GID and PRESERVE-EXTENDED-ATTRIBUTES are completely ignored."
   (setq filename (expand-file-name filename)
@@ -634,7 +652,8 @@ PRESERVE-UID-GID and PRESERVE-EXTENDED-ATTRIBUTES are completely ignored."
   (if (file-directory-p filename)
       (tramp-file-name-handler 'copy-directory filename newname keep-date t)
     (with-tramp-progress-reporter
-       (tramp-dissect-file-name (if (file-remote-p filename) filename newname))
+       (tramp-dissect-file-name
+        (if (tramp-tramp-file-p filename) filename newname))
        0 (format "Copying %s to %s" filename newname)
 
       (let ((tmpfile (file-local-copy filename)))
@@ -675,32 +694,36 @@ PRESERVE-UID-GID and PRESERVE-EXTENDED-ATTRIBUTES are completely ignored."
   (setq filename (expand-file-name filename)
        newname (expand-file-name newname))
 
-  (with-parsed-tramp-file-name
-      (if (file-remote-p filename) filename newname) nil
-    (with-tramp-progress-reporter
-       v 0 (format "Renaming %s to %s" newname filename)
-
-      (if (and (tramp-equal-remote filename newname)
-              (not (file-directory-p filename)))
-         (progn
-           (when (and (not ok-if-already-exists)
-                      (file-exists-p newname))
-             (tramp-error v 'file-already-exists newname))
-           ;; We must also flush the cache of the directory, because
-           ;; `file-attributes' reads the values from there.
-           (tramp-flush-file-property v (file-name-directory localname))
-           (tramp-flush-file-property v localname)
-           ;; Short track.
-           (tramp-adb-barf-unless-okay
-            v (format
-               "mv %s %s"
-               (tramp-file-name-handler 'file-remote-p filename 'localname)
-               localname)
-            "Error renaming %s to %s" filename newname))
-
-       ;; Rename by copy.
-       (copy-file filename newname ok-if-already-exists t t)
-       (delete-file filename)))))
+  (let ((t1 (tramp-tramp-file-p filename))
+       (t2 (tramp-tramp-file-p newname)))
+    (with-parsed-tramp-file-name (if t1 filename newname) nil
+      (with-tramp-progress-reporter
+         v 0 (format "Renaming %s to %s" filename newname)
+
+       (if (and t1 t2
+                (tramp-equal-remote filename newname)
+                (not (file-directory-p filename)))
+           (let ((l1 (tramp-file-name-handler
+                      'file-remote-p filename 'localname))
+                 (l2 (tramp-file-name-handler
+                      'file-remote-p newname 'localname)))
+             (when (and (not ok-if-already-exists)
+                        (file-exists-p newname))
+               (tramp-error v 'file-already-exists newname))
+             ;; We must also flush the cache of the directory, because
+             ;; `file-attributes' reads the values from there.
+             (tramp-flush-file-property v (file-name-directory l1))
+             (tramp-flush-file-property v l1)
+             (tramp-flush-file-property v (file-name-directory l2))
+             (tramp-flush-file-property v l2)
+             ;; Short track.
+             (tramp-adb-barf-unless-okay
+              v (format "mv %s %s" l1 l2)
+              "Error renaming %s to %s" filename newname))
+
+         ;; Rename by copy.
+         (copy-file filename newname ok-if-already-exists t t)
+         (delete-file filename))))))
 
 (defun tramp-adb-handle-process-file
   (program &optional infile destination display &rest args)
@@ -771,16 +794,18 @@ PRESERVE-UID-GID and PRESERVE-EXTENDED-ATTRIBUTES are completely ignored."
       ;; directory.
       (condition-case nil
          (progn
-           (setq ret 0)
-           (tramp-adb-barf-unless-okay
-            v (format "(cd %s; %s)"
-                      (tramp-shell-quote-argument localname) command)
-            "")
-           ;; We should show the output anyway.
+           (setq ret
+                 (if (tramp-adb-send-command-and-check
+                      v
+                      (format "(cd %s; %s)"
+                              (tramp-shell-quote-argument localname) command))
+                     ;; Set return status accordingly.
+                     0 1))
+           ;; We should add the output anyway.
            (when outbuf
              (with-current-buffer outbuf
                (insert-buffer-substring (tramp-get-connection-buffer v)))
-             (when display (display-buffer outbuf))))
+             (when (and display (get-buffer-window outbuf t)) (redisplay))))
        ;; When the user did interrupt, we should do it also.  We use
        ;; return code -1 as marker.
        (quit
@@ -846,7 +871,7 @@ PRESERVE-UID-GID and PRESERVE-EXTENDED-ATTRIBUTES are completely ignored."
     (when p
       (if (yes-or-no-p "A command is running.  Kill it? ")
          (ignore-errors (kill-process p))
-       (tramp-compat-user-error "Shell command in progress")))
+       (tramp-user-error p "Shell command in progress")))
 
     (if current-buffer-p
        (progn
@@ -973,7 +998,8 @@ PRESERVE-UID-GID and PRESERVE-EXTENDED-ATTRIBUTES are completely ignored."
   (with-temp-buffer
     (prog1
        (unless
-           (zerop (apply 'tramp-call-process tramp-adb-program nil t nil args))
+           (zerop
+            (apply 'tramp-call-process vec tramp-adb-program nil t nil args))
          (buffer-string))
       (tramp-message vec 6 "%s" (buffer-string)))))
 
@@ -981,7 +1007,7 @@ PRESERVE-UID-GID and PRESERVE-EXTENDED-ATTRIBUTES are completely ignored."
   "Checks, whether the ash has a builtin \"test\" command.
 This happens for Android >= 4.0."
   (with-tramp-connection-property vec "test"
-    (zerop (tramp-adb-command-exit-status vec "type test"))))
+    (tramp-adb-send-command-and-check vec "type test")))
 
 ;; Connection functions
 
@@ -1004,11 +1030,12 @@ This happens for Android >= 4.0."
       (while (re-search-forward "\r+$" nil t)
        (replace-match "" nil nil)))))
 
-(defun tramp-adb-command-exit-status
+(defun tramp-adb-send-command-and-check
   (vec command)
-  "Run COMMAND and return its exit status.
-Sends `echo $?' along with the COMMAND for checking the exit status.  If
-COMMAND is nil, just sends `echo $?'.  Returns the exit status found."
+  "Run COMMAND and check its exit status.
+Sends `echo $?' along with the COMMAND for checking the exit
+status.  If COMMAND is nil, just sends `echo $?'.  Returns nil if
+the exit status is not equal 0, and t otherwise."
   (tramp-adb-send-command
    vec (if command
           (format "%s; echo tramp_exit_status $?" command)
@@ -1020,14 +1047,14 @@ COMMAND is nil, just sends `echo $?'.  Returns the exit status found."
        vec 'file-error "Couldn't find exit status of `%s'" command))
     (skip-chars-forward "^ ")
     (prog1
-       (read (current-buffer))
+       (zerop (read (current-buffer)))
       (let (buffer-read-only)
        (delete-region (match-beginning 0) (point-max))))))
 
 (defun tramp-adb-barf-unless-okay (vec command fmt &rest args)
   "Run COMMAND, check exit status, throw error if exit status not okay.
 FMT and ARGS are passed to `error'."
-  (unless (zerop (tramp-adb-command-exit-status vec command))
+  (unless (tramp-adb-send-command-and-check vec command)
     (apply 'tramp-error vec 'file-error fmt args)))
 
 (defun tramp-adb-wait-for-output (proc &optional timeout)
@@ -1064,11 +1091,13 @@ FMT and ARGS are passed to `error'."
   "Maybe open a connection VEC.
 Does not do anything if a connection is already open, but re-opens the
 connection if a previous connection has died for some reason."
+  (tramp-check-proper-method-and-host vec)
+
   (let* ((buf (tramp-get-connection-buffer vec))
         (p (get-buffer-process buf))
         (host (tramp-file-name-host vec))
         (user (tramp-file-name-user vec))
-        (devices (mapcar 'cadr (tramp-adb-parse-device-names nil))))
+        devices)
 
     ;; Maybe we know already that "su" is not supported.  We cannot
     ;; use a connection property, because we have not checked yet
@@ -1080,6 +1109,7 @@ connection if a previous connection has died for some reason."
        (and p (processp p) (memq (process-status p) '(run open)))
       (save-match-data
        (when (and p (processp p)) (delete-process p))
+       (setq devices (mapcar 'cadr (tramp-adb-parse-device-names nil)))
        (if (not devices)
            (tramp-error vec 'file-error "No device connected"))
        (if (and (> (length host) 0) (not (member host devices)))
@@ -1104,6 +1134,7 @@ connection if a previous connection has died for some reason."
            (tramp-adb-wait-for-output p 30)
            (unless (eq 'run (process-status p))
              (tramp-error  vec 'file-error "Terminated!"))
+           (tramp-set-connection-property p "vector" vec)
            (tramp-compat-set-process-query-on-exit-flag p nil)
 
            ;; Check whether the properties have been changed.  If
@@ -1123,17 +1154,17 @@ connection if a previous connection has died for some reason."
                      (read (current-buffer))))))
              (when (and (stringp old-getprop)
                         (not (string-equal old-getprop new-getprop)))
-               (tramp-cleanup vec)
                (tramp-message
                 vec 3
                 "Connection reset, because remote host changed from `%s' to `%s'"
                 old-getprop new-getprop)
+               (tramp-cleanup-connection vec t)
                (tramp-adb-maybe-open-connection vec)))
 
            ;; Change user if indicated.
            (when user
              (tramp-adb-send-command vec (format "su %s" user))
-             (unless (zerop (tramp-adb-command-exit-status vec nil))
+             (unless (tramp-adb-send-command-and-check vec nil)
                (delete-process p)
                (tramp-set-file-property vec "" "su-command-p" nil)
                (tramp-error
@@ -1151,5 +1182,9 @@ connection if a previous connection has died for some reason."
                (read (current-buffer)))
              ":" 'omit-nulls))))))))
 
+(add-hook 'tramp-unload-hook
+         (lambda ()
+           (unload-feature 'tramp-adb 'force)))
+
 (provide 'tramp-adb)
 ;;; tramp-adb.el ends here