;;; tramp-smb.el --- Tramp access functions for SMB servers -*- coding: iso-8859-1; -*-
-;; Copyright (C) 2002, 2003 Free Software Foundation, Inc.
+;; Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc.
;; Author: Michael Albinus <Michael.Albinus@alcatel.de>
;; Keywords: comm, processes
;; Add a default for `tramp-default-method-alist'. Rule: If there is
;; a domain in USER, it must be the SMB method.
(add-to-list 'tramp-default-method-alist
- (list "%" "" tramp-smb-method))
+ (list "" "%" tramp-smb-method))
;; Add completion function for SMB method.
(tramp-set-completion-function
:group 'tramp
:type 'string)
-(defconst tramp-smb-prompt "^smb: \\S-+> "
+(defconst tramp-smb-prompt "^smb: \\S-+> \\|^\\s-+Server\\s-+Comment$"
"Regexp used as prompt in smbclient.")
(defconst tramp-smb-errors
'(; Connection error
"Connection to \\S-+ failed"
; Samba
- "ERRSRV"
"ERRDOS"
+ "ERRSRV"
"ERRbadfile"
"ERRbadpw"
"ERRfilexists"
"ERRnosuchshare"
; Windows NT 4.0, Windows 5.0 (Windows 2000), Windows 5.1 (Windows XP)
"NT_STATUS_ACCESS_DENIED"
+ "NT_STATUS_ACCOUNT_LOCKED_OUT"
"NT_STATUS_BAD_NETWORK_NAME"
"NT_STATUS_CANNOT_DELETE"
"NT_STATUS_LOGON_FAILURE"
+ "NT_STATUS_NETWORK_ACCESS_DENIED"
"NT_STATUS_NO_SUCH_FILE"
"NT_STATUS_OBJECT_NAME_INVALID"
"NT_STATUS_OBJECT_NAME_NOT_FOUND"
- "NT_STATUS_SHARING_VIOLATION")
+ "NT_STATUS_SHARING_VIOLATION"
+ "NT_STATUS_WRONG_PASSWORD")
"\\|")
"Regexp for possible error strings of SMB servers.
Used instead of analyzing error codes of commands.")
This variable is local to each buffer.")
(make-variable-buffer-local 'tramp-smb-share-cache)
-(defvar tramp-smb-process-running nil
- "Flag whether a corresponding process is still running.
-Will be changed by corresponding `process-sentinel'.
-This variable is local to each buffer.")
-(make-variable-buffer-local 'tramp-smb-process-running)
-
(defvar tramp-smb-inodes nil
"Keeps virtual inodes numbers for SMB files.")
(defun tramp-smb-handle-file-writable-p (filename)
"Like `file-writable-p' for tramp files."
-; (with-parsed-tramp-file-name filename nil
- (let (user host localname)
- (with-parsed-tramp-file-name filename l
- (setq user l-user host l-host localname l-localname))
- (save-excursion
- (let* ((share (tramp-smb-get-share localname))
- (file (tramp-smb-get-localname localname nil))
- (entries (tramp-smb-get-file-entries user host share file))
- (entry (and entries
- (assoc (file-name-nondirectory file) entries))))
- (and entry
- (string-match "w" (nth 1 entry))
- t)))))
+ (if (not (file-exists-p filename))
+ (let ((dir (file-name-directory filename)))
+ (and (file-exists-p dir)
+ (file-writable-p dir)))
+; (with-parsed-tramp-file-name filename nil
+ (let (user host localname)
+ (with-parsed-tramp-file-name filename l
+ (setq user l-user host l-host localname l-localname))
+ (save-excursion
+ (let* ((share (tramp-smb-get-share localname))
+ (file (tramp-smb-get-localname localname nil))
+ (entries (tramp-smb-get-file-entries user host share file))
+ (entry (and entries
+ (assoc (file-name-nondirectory file) entries))))
+ (and share entry
+ (string-match "w" (nth 1 entry))
+ t))))))
(defun tramp-smb-handle-insert-directory
(filename switches &optional wildcard full-directory-p)
;; Cache share entries
(setq tramp-smb-share-cache res)))
-
;; Add directory itself
- (add-to-list 'res '("" "dr-xr-xr-x" 0 (0 0)))
+ (add-to-list 'res '("" "drwxrwxrwx" 0 (0 0)))
+
+ ;; There's a very strange error (debugged with XEmacs 21.4.14)
+ ;; If there's no short delay, it returns nil. No idea about
+ (when (featurep 'xemacs) (sleep-for 0.01))
;; Check for matching entries
(delq nil (mapcar
"Maybe open a connection to HOST, logging in as USER, using `tramp-smb-program'.
Does not do anything if a connection is already open, but re-opens the
connection if a previous connection has died for some reason."
- (let ((p (get-buffer-process
+ (let ((process-connection-type tramp-process-connection-type)
+ (p (get-buffer-process
(tramp-get-buffer nil tramp-smb-method user host))))
(save-excursion
(set-buffer (tramp-get-buffer nil tramp-smb-method user host))
(tramp-message 9 "Started process %s" (process-command p))
(process-kill-without-query p)
(set-buffer buffer)
- (set-process-sentinel
- p (lambda (proc str) (setq tramp-smb-process-running nil)))
- ; If no share is given, the process will terminate
- (setq tramp-smb-process-running share
- tramp-smb-share share)
+ (setq tramp-smb-share share)
; send password
(when real-user
(tramp-enter-password p pw-prompt)))
(unless (tramp-smb-wait-for-output user host)
+ (tramp-clear-passwd user host)
(error "Cannot open connection //%s@%s/%s"
user host (or share "")))))))
;; We don't use timeouts. If needed, the caller shall wrap around.
(defun tramp-smb-wait-for-output (user host)
"Wait for output from smbclient command.
-Sets position to begin of buffer.
Returns nil if an error message has appeared."
- (save-excursion
- (let ((proc (get-buffer-process (current-buffer)))
- (found (progn (goto-char (point-max))
- (beginning-of-line)
- (looking-at tramp-smb-prompt)))
- err)
- (save-match-data
- ;; Algorithm: get waiting output. See if last line contains
- ;; tramp-smb-prompt sentinel, or process has exited.
- ;; If not, wait a bit and again get waiting output.
- (while (and (not found) tramp-smb-process-running)
- (accept-process-output proc)
- (goto-char (point-max))
- (beginning-of-line)
- (setq found (looking-at tramp-smb-prompt)))
-
- ;; There might be pending output. If tramp-smb-prompt sentinel
- ;; hasn't been found, the process has died already. We should
- ;; give it a chance.
- (when (not found) (accept-process-output nil 1))
-
- ;; Search for errors.
- (goto-char (point-min))
- (setq err (re-search-forward tramp-smb-errors nil t)))
-
- ;; Add output to debug buffer if appropriate.
- (when tramp-debug-buffer
- (append-to-buffer
- (tramp-get-debug-buffer nil tramp-smb-method user host)
- (point-min) (point-max))
- (when (and (not found) tramp-smb-process-running)
- (save-excursion
- (set-buffer
- (tramp-get-debug-buffer nil tramp-smb-method user host))
- (goto-char (point-max))
- (insert (format "[[Remote prompt `%s' not found]]\n"
- tramp-smb-prompt)))))
+ (let ((proc (get-buffer-process (current-buffer)))
+ (found (progn (goto-char (point-min))
+ (re-search-forward tramp-smb-prompt nil t)))
+ (err (progn (goto-char (point-min))
+ (re-search-forward tramp-smb-errors nil t))))
+
+ ;; Algorithm: get waiting output. See if last line contains
+ ;; tramp-smb-prompt sentinel or tramp-smb-errors strings.
+ ;; If not, wait a bit and again get waiting output.
+ (while (and (not found) (not err))
+
+ ;; Accept pending output.
+ (accept-process-output proc)
+
+ ;; Search for prompt.
(goto-char (point-min))
- ;; Return value is whether no error message has appeared.
- (not err))))
+ (setq found (re-search-forward tramp-smb-prompt nil t))
+
+ ;; Search for errors.
+ (goto-char (point-min))
+ (setq err (re-search-forward tramp-smb-errors nil t)))
+
+ ;; Add output to debug buffer if appropriate.
+ (when tramp-debug-buffer
+ (append-to-buffer
+ (tramp-get-debug-buffer nil tramp-smb-method user host)
+ (point-min) (point-max)))
+
+ ;; Return value is whether no error message has appeared.
+ (not err)))
;; Snarfed code from time-date.el and parse-time.el
;; * Provide a local smb.conf. The default one might not be readable.
;; * Error handling in case password is wrong.
;; * Read password from "~/.netrc".
-;; * Use different buffers for different shares. By this, the password
-;; won't be requested again when changing shares on the same host.
;; * Return more comprehensive file permission string. Think whether it is
;; possible to implement `set-file-modes'.
;; * Handle WILDCARD and FULL-DIRECTORY-P in
;;; -*- mode: Emacs-Lisp; coding: iso-2022-7bit; -*-
;;; tramp.el --- Transparent Remote Access, Multiple Protocol
-;; Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
+;; Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
;; Author: kai.grossjohann@gmx.net
;; Keywords: comm, processes
(require 'timer)
(require 'format-spec) ;from Gnus 5.8, also in tar ball
+;; As long as password.el is not part of (X)Emacs, it shouldn't
+;; be mandatory
+(if (featurep 'xemacs)
+ (load "password" 'noerror)
+ (require 'password nil 'noerror)) ;from No Gnus, also in tar ball
+
;; The explicit check is not necessary in Emacs, which provides the
;; feature even if implemented in C, but it appears to be necessary
;; in XEmacs.
;; Default values for non-Unices seeked
(defconst tramp-completion-function-alist-ssh
(unless (memq system-type '(windows-nt))
- '((tramp-parse-rhosts "/etc/hosts.equiv")
- (tramp-parse-rhosts "/etc/shosts.equiv")
- (tramp-parse-shosts "/etc/ssh_known_hosts")
- (tramp-parse-sconfig "/etc/ssh_config")
- (tramp-parse-rhosts "~/.rhosts")
- (tramp-parse-rhosts "~/.shosts")
- (tramp-parse-shosts "~/.ssh/known_hosts")
- (tramp-parse-sconfig "~/.ssh/config")))
+ '((tramp-parse-rhosts "/etc/hosts.equiv")
+ (tramp-parse-rhosts "/etc/shosts.equiv")
+ (tramp-parse-shosts "/etc/ssh_known_hosts")
+ (tramp-parse-sconfig "/etc/ssh_config")
+ (tramp-parse-shostkeys "/etc/ssh2/hostkeys")
+ (tramp-parse-sknownhosts "/etc/ssh2/knownhosts")
+ (tramp-parse-rhosts "~/.rhosts")
+ (tramp-parse-rhosts "~/.shosts")
+ (tramp-parse-shosts "~/.ssh/known_hosts")
+ (tramp-parse-sconfig "~/.ssh/config")
+ (tramp-parse-shostkeys "~/.ssh2/hostkeys")
+ (tramp-parse-sknownhosts "~/.ssh2/knownhosts")))
"Default list of (FUNCTION FILE) pairs to be examined for ssh methods.")
;; Default values for non-Unices seeked
'((tramp-parse-passwd "/etc/passwd")))
"Default list of (FUNCTION FILE) pairs to be examined for su methods.")
-(defcustom tramp-completion-function-alist
- (list (cons "rcp" tramp-completion-function-alist-rsh)
- (cons "scp" tramp-completion-function-alist-ssh)
- (cons "scp1" tramp-completion-function-alist-ssh)
- (cons "scp2" tramp-completion-function-alist-ssh)
- (cons "scp1_old" tramp-completion-function-alist-ssh)
- (cons "scp2_old" tramp-completion-function-alist-ssh)
- (cons "rsync" tramp-completion-function-alist-rsh)
- (cons "remcp" tramp-completion-function-alist-rsh)
- (cons "rsh" tramp-completion-function-alist-rsh)
- (cons "ssh" tramp-completion-function-alist-ssh)
- (cons "ssh1" tramp-completion-function-alist-ssh)
- (cons "ssh2" tramp-completion-function-alist-ssh)
- (cons "ssh1_old" tramp-completion-function-alist-ssh)
- (cons "ssh2_old" tramp-completion-function-alist-ssh)
- (cons "remsh" tramp-completion-function-alist-rsh)
- (cons "telnet" tramp-completion-function-alist-telnet)
- (cons "su" tramp-completion-function-alist-su)
- (cons "sudo" tramp-completion-function-alist-su)
- (cons "multi" nil)
- (cons "scpx" tramp-completion-function-alist-ssh)
- (cons "sshx" tramp-completion-function-alist-ssh)
- (cons "krlogin" tramp-completion-function-alist-rsh)
- (cons "plink" tramp-completion-function-alist-ssh)
- (cons "plink1" tramp-completion-function-alist-ssh)
- (cons "pscp" tramp-completion-function-alist-ssh)
- (cons "fcp" tramp-completion-function-alist-ssh)
- )
+(defvar tramp-completion-function-alist nil
"*Alist of methods for remote files.
This is a list of entries of the form (NAME PAIR1 PAIR2 ...).
Each NAME stands for a remote access method. Each PAIR is of the form
\(FUNCTION FILE). FUNCTION is responsible to extract user names and host
names from FILE for completion. The following predefined FUNCTIONs exists:
- * `tramp-parse-rhosts' for \"~/.rhosts\" like files,
- * `tramp-parse-shosts' for \"~/.ssh/known_hosts\" like files,
- * `tramp-parse-sconfig' for \"~/.ssh/config\" like files,
- * `tramp-parse-hosts' for \"/etc/hosts\" like files, and
- * `tramp-parse-passwd' for \"/etc/passwd\" like files.
- * `tramp-parse-netrc' for \"~/.netrc\" like files.
-
-FUNCTION can also see a customer defined function. For more details see
-the info pages."
- :group 'tramp
- :type '(repeat
- (cons string
- (choice (const nil) (repeat (list function file))))))
+ * `tramp-parse-rhosts' for \"~/.rhosts\" like files,
+ * `tramp-parse-shosts' for \"~/.ssh/known_hosts\" like files,
+ * `tramp-parse-sconfig' for \"~/.ssh/config\" like files,
+ * `tramp-parse-shostkeys' for \"~/.ssh2/hostkeys/*\" like files,
+ * `tramp-parse-sknownhosts' for \"~/.ssh2/knownhosts/*\" like files,
+ * `tramp-parse-hosts' for \"/etc/hosts\" like files,
+ * `tramp-parse-passwd' for \"/etc/passwd\" like files.
+ * `tramp-parse-netrc' for \"~/.netrc\" like files.
+
+FUNCTION can also be a customer defined function. For more details see
+the info pages.")
+
+(eval-after-load "tramp"
+ '(progn
+ (tramp-set-completion-function
+ "rcp" tramp-completion-function-alist-rsh)
+ (tramp-set-completion-function
+ "scp" tramp-completion-function-alist-ssh)
+ (tramp-set-completion-function
+ "scp1" tramp-completion-function-alist-ssh)
+ (tramp-set-completion-function
+ "scp2" tramp-completion-function-alist-ssh)
+ (tramp-set-completion-function
+ "scp1_old" tramp-completion-function-alist-ssh)
+ (tramp-set-completion-function
+ "scp2_old" tramp-completion-function-alist-ssh)
+ (tramp-set-completion-function
+ "rsync" tramp-completion-function-alist-rsh)
+ (tramp-set-completion-function
+ "remcp" tramp-completion-function-alist-rsh)
+ (tramp-set-completion-function
+ "rsh" tramp-completion-function-alist-rsh)
+ (tramp-set-completion-function
+ "ssh" tramp-completion-function-alist-ssh)
+ (tramp-set-completion-function
+ "ssh1" tramp-completion-function-alist-ssh)
+ (tramp-set-completion-function
+ "ssh2" tramp-completion-function-alist-ssh)
+ (tramp-set-completion-function
+ "ssh1_old" tramp-completion-function-alist-ssh)
+ (tramp-set-completion-function
+ "ssh2_old" tramp-completion-function-alist-ssh)
+ (tramp-set-completion-function
+ "remsh" tramp-completion-function-alist-rsh)
+ (tramp-set-completion-function
+ "telnet" tramp-completion-function-alist-telnet)
+ (tramp-set-completion-function
+ "su" tramp-completion-function-alist-su)
+ (tramp-set-completion-function
+ "sudo" tramp-completion-function-alist-su)
+ (tramp-set-completion-function
+ "multi" nil)
+ (tramp-set-completion-function
+ "scpx" tramp-completion-function-alist-ssh)
+ (tramp-set-completion-function
+ "sshx" tramp-completion-function-alist-ssh)
+ (tramp-set-completion-function
+ "krlogin" tramp-completion-function-alist-rsh)
+ (tramp-set-completion-function
+ "plink" tramp-completion-function-alist-ssh)
+ (tramp-set-completion-function
+ "plink1" tramp-completion-function-alist-ssh)
+ (tramp-set-completion-function
+ "pscp" tramp-completion-function-alist-ssh)
+ (tramp-set-completion-function
+ "fcp" tramp-completion-function-alist-ssh)))
(defcustom tramp-rsh-end-of-line "\n"
"*String used for end of line in rsh connections.
:group 'tramp
:type '(choice (const nil) integer))
+;; Logging in to a remote host normally requires obtaining a pty. But
+;; Emacs on MacOS X has process-connection-type set to nil by default,
+;; so on those systems Tramp doesn't obtain a pty. Here, we allow
+;; for an override of the system default.
+(defcustom tramp-process-connection-type t
+ "Overrides `process-connection-type' for connections from Tramp.
+Tramp binds process-connection-type to the value given here before
+opening a connection to a remote host."
+ :group 'tramp
+ :type '(choice (const nil) (const t) (const pty)))
+
;;; Internal Variables:
(defvar tramp-buffer-file-attributes nil
(insert-file-contents . tramp-handle-insert-file-contents)
(write-region . tramp-handle-write-region)
(unhandled-file-name-directory . tramp-handle-unhandled-file-name-directory)
+ (dired-compress-file . tramp-handle-dired-compress-file)
(dired-call-process . tramp-handle-dired-call-process)
(dired-recursive-delete-directory
. tramp-handle-dired-recursive-delete-directory)
'((tramp-parse-sconfig \"/etc/ssh_config\")
(tramp-parse-sconfig \"~/.ssh/config\")))"
- (let ((v (cdr (assoc method tramp-completion-function-alist))))
- (if v (setcdr v function-list)
+ (let ((r function-list)
+ (v function-list))
+ (setq tramp-completion-function-alist
+ (delete (assoc method tramp-completion-function-alist)
+ tramp-completion-function-alist))
+
+ (while v
+ ;; Remove double entries
+ (when (member (car v) (cdr v))
+ (setcdr v (delete (car v) (cdr v))))
+ ;; Check for function and file
+ (unless (and (functionp (nth 0 (car v)))
+ (file-exists-p (nth 1 (car v))))
+ (setq r (delete (car v) r)))
+ (setq v (cdr v)))
+
+ (when r
(add-to-list 'tramp-completion-function-alist
- (cons method function-list)))))
+ (cons method r)))))
(defun tramp-get-completion-function (method)
"Returns list of completion functions for METHOD.
For definition of that list see `tramp-set-completion-function'."
- (cdr (assoc method tramp-completion-function-alist)))
+ (cdr (assoc method tramp-completion-function-alist)))
;;; File Name Handler Functions:
(signal 'file-already-exists
(list newname))))
(let ((t1 (tramp-tramp-file-p filename))
- (t2 (tramp-tramp-file-p newname)))
+ (t2 (tramp-tramp-file-p newname))
+ v1-multi-method v1-method v1-user v1-host v1-localname
+ v2-multi-method v2-method v2-user v2-host v2-localname)
+
;; Check which ones of source and target are Tramp files.
+ ;; We cannot invoke `with-parsed-tramp-file-name';
+ ;; it fails if the file isn't a Tramp file name.
+ (if t1
+ (with-parsed-tramp-file-name filename l
+ (setq v1-multi-method l-multi-method
+ v1-method l-method
+ v1-user l-user
+ v1-host l-host
+ v1-localname l-localname))
+ (setq v1-localname filename))
+ (if t2
+ (with-parsed-tramp-file-name newname l
+ (setq v2-multi-method l-multi-method
+ v2-method l-method
+ v2-user l-user
+ v2-host l-host
+ v2-localname l-localname))
+ (setq v2-localname newname))
+
(cond
+ ;; Both are Tramp files.
((and t1 t2)
- ;; Both are Tramp files.
- (with-parsed-tramp-file-name filename v1
- (with-parsed-tramp-file-name newname v2
- ;; Check if we can use a shortcut.
- (if (and (equal v1-multi-method v2-multi-method)
- (equal v1-method v2-method)
- (equal v1-host v2-host)
- (equal v1-user v2-user))
- ;; Shortcut: if method, host, user are the same for both
- ;; files, we invoke `cp' or `mv' on the remote host
- ;; directly.
- (tramp-do-copy-or-rename-file-directly
- op v1-multi-method v1-method v1-user v1-host
- v1-localname v2-localname keep-date)
- ;; The shortcut was not possible. So we copy the
- ;; file first. If the operation was `rename', we go
- ;; back and delete the original file (if the copy was
- ;; successful). The approach is simple-minded: we
- ;; create a new buffer, insert the contents of the
- ;; source file into it, then write out the buffer to
- ;; the target file. The advantage is that it doesn't
- ;; matter which filename handlers are used for the
- ;; source and target file.
-
- ;; CCC: If both source and target are Tramp files,
- ;; and both are using the same copy-program, then we
- ;; can invoke rcp directly. Note that
- ;; default-directory should point to a local
- ;; directory if we want to invoke rcp.
- (tramp-do-copy-or-rename-via-buffer
- op filename newname keep-date)))))
+ (cond
+ ;; Shortcut: if method, host, user are the same for both
+ ;; files, we invoke `cp' or `mv' on the remote host
+ ;; directly.
+ ((and (equal v1-multi-method v2-multi-method)
+ (equal v1-method v2-method)
+ (equal v1-user v2-user)
+ (equal v1-host v2-host))
+ (tramp-do-copy-or-rename-file-directly
+ op v1-multi-method v1-method v1-user v1-host
+ v1-localname v2-localname keep-date))
+ ;; If both source and target are Tramp files,
+ ;; both are using the same copy-program, then we
+ ;; can invoke rcp directly. Note that
+ ;; default-directory should point to a local
+ ;; directory if we want to invoke rcp.
+ ((and (not v1-multi-method)
+ (not v2-multi-method)
+ (equal v1-method v2-method)
+ (tramp-method-out-of-band-p
+ v1-multi-method v1-method v1-user v1-host)
+ (not (string-match "\\([^#]*\\)#\\(.*\\)" v1-host))
+ (not (string-match "\\([^#]*\\)#\\(.*\\)" v2-host)))
+ (tramp-do-copy-or-rename-file-out-of-band
+ op filename newname keep-date))
+ ;; No shortcut was possible. So we copy the
+ ;; file first. If the operation was `rename', we go
+ ;; back and delete the original file (if the copy was
+ ;; successful). The approach is simple-minded: we
+ ;; create a new buffer, insert the contents of the
+ ;; source file into it, then write out the buffer to
+ ;; the target file. The advantage is that it doesn't
+ ;; matter which filename handlers are used for the
+ ;; source and target file.
+ (t
+ (tramp-do-copy-or-rename-via-buffer
+ op filename newname keep-date))))
+
+ ;; One file is a Tramp file, the other one is local.
((or t1 t2)
- ;; Use the generic method via a Tramp buffer.
- (tramp-do-copy-or-rename-via-buffer op filename newname keep-date))
+ ;; If the Tramp file has an out-of-band method, the corresponding
+ ;; copy-program can be invoked.
+ (if (and (not v1-multi-method)
+ (not v2-multi-method)
+ (or (tramp-method-out-of-band-p
+ v1-multi-method v1-method v1-user v1-host)
+ (tramp-method-out-of-band-p
+ v2-multi-method v2-method v2-user v2-host)))
+ (tramp-do-copy-or-rename-file-out-of-band
+ op filename newname keep-date)
+ ;; Use the generic method via a Tramp buffer.
+ (tramp-do-copy-or-rename-via-buffer op filename newname keep-date)))
+
(t
;; One of them must be a Tramp file.
(error "Tramp implementation says this cannot happen")))))
First arg OP is either `copy' or `rename' and indicates the operation.
FILENAME is the source file, NEWNAME the target file.
KEEP-DATE is non-nil if NEWNAME should have the same timestamp as FILENAME."
- (let ((trampbuf (get-buffer-create "*tramp output*")))
- (when keep-date
+ (let ((trampbuf (get-buffer-create "*tramp output*"))
+ (modtime (nth 5 (file-attributes filename))))
+ (when (and keep-date (or (null modtime) (equal modtime '(0 0))))
(tramp-message
1 (concat "Warning: cannot preserve file time stamp"
" with inline copying across machines")))
;; `jka-compr-inhibit' to t.
(let ((coding-system-for-write 'binary)
(jka-compr-inhibit t))
- (write-region (point-min) (point-max) newname)))
+ (write-region (point-min) (point-max) newname))
+ ;; KEEP-DATE handling.
+ (when (and keep-date
+ (not (null modtime))
+ (not (equal modtime '(0 0))))
+ (tramp-touch newname modtime)))
;; If the operation was `rename', delete the original file.
(unless (eq op 'copy)
(delete-file filename))))
"Copying directly failed, see buffer `%s' for details."
(buffer-name)))))
-(defun tramp-do-copy-or-rename-file-one-local
- (op filename newname keep-date)
+(defun tramp-do-copy-or-rename-file-out-of-band (op filename newname keep-date)
"Invoke rcp program to copy.
One of FILENAME and NEWNAME must be a Tramp name, the other must
be a local filename. The method used must be an out-of-band method."
- ;; CCC
- )
+ (let ((trampbuf (get-buffer-create "*tramp output*"))
+ (t1 (tramp-tramp-file-p filename))
+ (t2 (tramp-tramp-file-p newname))
+ v1-multi-method v1-method v1-user v1-host v1-localname
+ v2-multi-method v2-method v2-user v2-host v2-localname
+ method copy-program copy-args source target)
+
+ ;; Check which ones of source and target are Tramp files.
+ ;; We cannot invoke `with-parsed-tramp-file-name';
+ ;; it fails if the file isn't a Tramp file name.
+ (if t1
+ (with-parsed-tramp-file-name filename l
+ (setq v1-multi-method l-multi-method
+ v1-method l-method
+ v1-user l-user
+ v1-host l-host
+ v1-localname l-localname
+ method (tramp-find-method
+ v1-multi-method v1-method v1-user v1-host)
+ copy-program (tramp-get-method-parameter
+ v1-multi-method method
+ v1-user v1-host 'tramp-copy-program)
+ copy-args (tramp-get-method-parameter
+ v1-multi-method method
+ v1-user v1-host 'tramp-copy-args)))
+ (setq v1-localname filename))
+
+ (if t2
+ (with-parsed-tramp-file-name newname l
+ (setq v2-multi-method l-multi-method
+ v2-method l-method
+ v2-user l-user
+ v2-host l-host
+ v2-localname l-localname
+ method (tramp-find-method
+ v2-multi-method v2-method v2-user v2-host)
+ copy-program (tramp-get-method-parameter
+ v2-multi-method method
+ v2-user v2-host 'tramp-copy-program)
+ copy-args (tramp-get-method-parameter
+ v2-multi-method method
+ v2-user v2-host 'tramp-copy-args)))
+ (setq v2-localname newname))
+
+ ;; The following should be changed. We need a more general
+ ;; mechanism to parse extra host args.
+ (if (not t1)
+ (setq source v1-localname)
+ (when (string-match "\\([^#]*\\)#\\(.*\\)" v1-host)
+ (setq copy-args (cons "-P" (cons (match-string 2 v1-host) copy-args)))
+ (setq v1-host (match-string 1 v1-host)))
+ (setq source
+ (tramp-make-copy-program-file-name
+ v1-user v1-host
+ (tramp-shell-quote-argument v1-localname))))
+
+ (if (not t2)
+ (setq target v2-localname)
+ (when (string-match "\\([^#]*\\)#\\(.*\\)" v2-host)
+ (setq copy-args (cons "-P" (cons (match-string 2 v2-host) copy-args)))
+ (setq v2-host (match-string 1 v2-host)))
+ (setq target
+ (tramp-make-copy-program-file-name
+ v2-user v2-host
+ (tramp-shell-quote-argument v2-localname))))
+
+ ;; Handle keep-date argument
+ (when keep-date
+ (if t1
+ (setq copy-args
+ (cons (tramp-get-method-parameter
+ v1-multi-method method
+ v1-user v1-host 'tramp-copy-keep-date-arg)
+ copy-args))
+ (setq copy-args
+ (cons (tramp-get-method-parameter
+ v2-multi-method method
+ v2-user v2-host 'tramp-copy-keep-date-arg)
+ copy-args))))
+
+ (setq copy-args (append copy-args (list source target)))
+
+ ;; Use rcp-like program for file transfer.
+ (tramp-message
+ 5 "Transferring %s to file %s..." filename newname)
+ (save-excursion (set-buffer trampbuf) (erase-buffer))
+ (unless (equal
+ 0
+ (apply #'call-process copy-program
+ nil trampbuf nil copy-args))
+ (pop-to-buffer trampbuf)
+ (error
+ (concat
+ "tramp-do-copy-or-rename-file-out-of-band: `%s' didn't work, "
+ "see buffer `%s' for details")
+ copy-program trampbuf))
+ (tramp-message
+ 5 "Transferring %s to file %s...done" filename newname)
+
+ ;; If the operation was `rename', delete the original file.
+ (unless (eq op 'copy)
+ (delete-file filename))))
;; mkdir
(defun tramp-handle-make-directory (dir &optional parents)
(and (tramp-handle-file-exists-p filename)
(error "Failed to recusively delete %s" filename))))
-
(defun tramp-handle-dired-call-process (program discard &rest arguments)
"Like `dired-call-process' for tramp files."
(with-parsed-tramp-file-name default-directory nil
(tramp-send-command-and-check multi-method method user host nil)
(tramp-send-command multi-method method user host "cd")
(tramp-wait-for-output)))))
+
+(defun tramp-handle-dired-compress-file (file &rest ok-flag)
+ "Like `dired-compress-file' for tramp files."
+ ;; OK-FLAG is valid for XEmacs only, but not implemented.
+ ;; Code stolen mainly from dired-aux.el.
+ (with-parsed-tramp-file-name file nil
+ (save-excursion
+ (let ((suffixes
+ (if (not (featurep 'xemacs))
+ ;; Emacs case
+ (symbol-value 'dired-compress-file-suffixes)
+ ;; XEmacs has `dired-compression-method-alist', which is
+ ;; transformed into `dired-compress-file-suffixes' structure.
+ (mapcar
+ '(lambda (x)
+ (list (concat (regexp-quote (nth 1 x)) "\\'")
+ nil
+ (mapconcat 'identity (nth 3 x) " ")))
+ (symbol-value 'dired-compression-method-alist))))
+ suffix)
+ ;; See if any suffix rule matches this file name.
+ (while suffixes
+ (let (case-fold-search)
+ (if (string-match (car (car suffixes)) localname)
+ (setq suffix (car suffixes) suffixes nil))
+ (setq suffixes (cdr suffixes))))
+
+ (cond ((file-symlink-p file)
+ nil)
+ ((and suffix (nth 2 suffix))
+ ;; We found an uncompression rule.
+ (message "Uncompressing %s..." file)
+ (when (zerop (tramp-send-command-and-check
+ multi-method method user host
+ (concat (nth 2 suffix) " " localname)))
+ (message "Uncompressing %s...done" file)
+ (dired-remove-file file)
+ (string-match (car suffix) file)
+ (concat (substring file 0 (match-beginning 0)))))
+ (t
+ ;; We don't recognize the file as compressed, so compress it.
+ ;; Try gzip.
+ (message "Compressing %s..." file)
+ (when (zerop (tramp-send-command-and-check
+ multi-method method user host
+ (concat "gzip -f " localname)))
+ (message "Compressing %s...done" file)
+ (dired-remove-file file)
+ (cond ((file-exists-p (concat file ".gz"))
+ (concat file ".gz"))
+ ((file-exists-p (concat file ".z"))
+ (concat file ".z"))
+ (t nil)))))))))
;; Pacify byte-compiler. The function is needed on XEmacs only. I'm
;; not sure at all that this is the right way to do it, but let's hope
;; Remote commands.
+(defvar tramp-async-proc nil
+ "Global variable keeping asyncronous process object.
+Used in `tramp-handle-shell-command'")
+
(defun tramp-handle-shell-command (command &optional output-buffer error-buffer)
"Like `shell-command' for tramp files.
This will break if COMMAND prints a newline, followed by the value of
`tramp-end-of-output', followed by another newline."
+ ;; Asynchronous processes are far from being perfect. But it works at least
+ ;; for `find-grep-dired' and `find-name-dired' in Emacs 21.4.
(if (tramp-tramp-file-p default-directory)
(with-parsed-tramp-file-name default-directory nil
- (let (status)
- (when (string-match "&[ \t]*\\'" command)
- (error "Tramp doesn't grok asynchronous shell commands, yet"))
-;; (when error-buffer
-;; (error "Tramp doesn't grok optional third arg ERROR-BUFFER, yet"))
+ (let ((asynchronous (string-match "[ \t]*&[ \t]*\\'" command))
+ status)
+ (unless output-buffer
+ (setq output-buffer
+ (get-buffer-create
+ (if asynchronous
+ "*Async Shell Command*"
+ "*Shell Command Output*")))
+ (set-buffer output-buffer)
+ (erase-buffer))
+ (unless (bufferp output-buffer)
+ (setq output-buffer (current-buffer)))
+ (set-buffer output-buffer)
+ ;; Tramp doesn't handle the asynchronous case by an asynchronous
+ ;; process. Instead of, another asynchronous process is opened
+ ;; which gets the output of the (synchronous) Tramp process
+ ;; via process-filter. ERROR-BUFFER is disabled.
+ (when asynchronous
+ (setq command (substring command 0 (match-beginning 0))
+ error-buffer nil
+ tramp-async-proc (start-process (buffer-name output-buffer)
+ output-buffer "cat")))
(save-excursion
(tramp-barf-unless-okay
multi-method method user host
nil 'file-error
"tramp-handle-shell-command: Couldn't `cd %s'"
(tramp-shell-quote-argument localname))
+ ;; Define the process filter
+ (when asynchronous
+ (set-process-filter
+ (get-buffer-process
+ (tramp-get-buffer multi-method method user host))
+ '(lambda (process string)
+ ;; Write the output into the Tramp Process
+ (save-current-buffer
+ (set-buffer (process-buffer process))
+ (goto-char (point-max))
+ (insert string))
+ ;; Hand-over output to asynchronous process.
+ (let ((end
+ (string-match
+ (regexp-quote tramp-end-of-output) string)))
+ (when end
+ (setq string
+ (substring string 0 (1- (match-beginning 0)))))
+ (process-send-string tramp-async-proc string)
+ (when end
+ (set-process-filter process nil)
+ (process-send-eof tramp-async-proc))))))
+ ;; Send the command
(tramp-send-command
multi-method method user host
(if error-buffer
(format "( %s ) 2>/tmp/tramp.$$.err; tramp_old_status=$?"
command)
- (format "%s ;tramp_old_status=$?" command)))
- ;; This will break if the shell command prints "/////"
- ;; somewhere. Let's just hope for the best...
- (tramp-wait-for-output))
- (unless output-buffer
- (setq output-buffer (get-buffer-create "*Shell Command Output*"))
- (set-buffer output-buffer)
- (erase-buffer))
- (unless (bufferp output-buffer)
- (setq output-buffer (current-buffer)))
- (set-buffer output-buffer)
- (insert-buffer (tramp-get-buffer multi-method method user host))
+ (format "%s; tramp_old_status=$?" command)))
+ (unless asynchronous
+ (tramp-wait-for-output)))
+ (unless asynchronous
+ (insert-buffer (tramp-get-buffer multi-method method user host)))
(when error-buffer
(save-excursion
(unless (bufferp error-buffer)
multi-method method user host "rm -f /tmp/tramp.$$.err")))
(save-excursion
(tramp-send-command multi-method method user host "cd")
- (tramp-wait-for-output)
+ (unless asynchronous
+ (tramp-wait-for-output))
(tramp-send-command
multi-method method user host
(concat "tramp_set_exit_status $tramp_old_status;"
" echo tramp_exit_status $?"))
- (tramp-wait-for-output)
- (goto-char (point-max))
- (unless (search-backward "tramp_exit_status " nil t)
- (error "Couldn't find exit status of `%s'" command))
- (skip-chars-forward "^ ")
- (setq status (read (current-buffer))))
+ (unless asynchronous
+ (tramp-wait-for-output)
+ (goto-char (point-max))
+ (unless (search-backward "tramp_exit_status " nil t)
+ (error "Couldn't find exit status of `%s'" command))
+ (skip-chars-forward "^ ")
+ (setq status (read (current-buffer)))))
(unless (zerop (buffer-size))
(display-buffer output-buffer))
status))
(defun tramp-handle-file-local-copy (filename)
"Like `file-local-copy' for tramp files."
(with-parsed-tramp-file-name filename nil
- (let ((output-buf (get-buffer-create "*tramp output*"))
- (tramp-buf (tramp-get-buffer multi-method method user host))
- (copy-program (tramp-get-method-parameter
- multi-method
- (tramp-find-method multi-method method user host)
- user host 'tramp-copy-program))
- (copy-args (tramp-get-method-parameter
- multi-method
- (tramp-find-method multi-method method user host)
- user host 'tramp-copy-args))
+ (let ((tramp-buf (tramp-get-buffer multi-method method user host))
;; We used to bind the following as late as possible.
;; loc-enc and loc-dec were bound directly before the if
;; statement that checks them. But the functions
(error "Cannot make local copy of non-existing file `%s'"
filename))
(setq tmpfil (tramp-make-temp-file))
- (cond (copy-program
- ;; The following should be changed. We need a more general
- ;; mechanism to parse extra host args.
- (when (string-match "\\([^#]*\\)#\\(.*\\)" host)
- (setq copy-args (cons "-p" (cons (match-string 2 host)
- rsh-args)))
- (setq host (match-string 1 host)))
- ;; Use rcp-like program for file transfer.
- (tramp-message-for-buffer
- multi-method method user host
- 5 "Fetching %s to tmp file %s..." filename tmpfil)
- (save-excursion (set-buffer output-buf) (erase-buffer))
- (unless (equal
- 0
- (apply #'call-process
- copy-program
- nil output-buf nil
- (append copy-args
- (list
- (tramp-make-copy-program-file-name
- user host
- (tramp-shell-quote-argument localname))
- tmpfil))))
- (pop-to-buffer output-buf)
- (error
- (concat "tramp-handle-file-local-copy: `%s' didn't work, "
- "see buffer `%s' for details")
- copy-program output-buf))
- (tramp-message-for-buffer
- multi-method method user host
- 5 "Fetching %s to tmp file %s...done" filename tmpfil))
+
+
+ (cond ((tramp-method-out-of-band-p multi-method method user host)
+ ;; `copy-file' handles out-of-band methods
+ (copy-file filename tmpfil t t))
+
((and rem-enc rem-dec)
;; Use inline encoding for file transfer.
(save-excursion
(error "File not overwritten")))
(with-parsed-tramp-file-name filename nil
(let ((curbuf (current-buffer))
- (copy-program (tramp-get-method-parameter
- multi-method
- (tramp-find-method multi-method method user host)
- user host 'tramp-copy-program))
- (copy-args (tramp-get-method-parameter
- multi-method
- (tramp-find-method multi-method method user host)
- user host 'tramp-copy-args))
(rem-enc (tramp-get-remote-encoding multi-method method user host))
(rem-dec (tramp-get-remote-decoding multi-method method user host))
(loc-enc (tramp-get-local-encoding multi-method method user host))
;; decoding command must be specified. However, if the method
;; _also_ specifies an encoding function, then that is used for
;; encoding the contents of the tmp file.
- (cond (copy-program
- ;; The following should be changed. We need a more general
- ;; mechanism to parse extra host args.
- (when (string-match "\\([^#]*\\)#\\(.*\\)" host)
- (setq copy-args (cons "-p" (cons (match-string 2 host)
- rsh-args)))
- (setq host (match-string 1 host)))
-
- ;; use rcp-like program for file transfer
- (let ((argl (append copy-args
- (list
- tmpfil
- (tramp-make-copy-program-file-name
- user host
- (tramp-shell-quote-argument localname))))))
- (tramp-message-for-buffer
- multi-method method user host
- 6 "Writing tmp file using `%s'..." copy-program)
- (save-excursion (set-buffer trampbuf) (erase-buffer))
- (when tramp-debug-buffer
- (save-excursion
- (set-buffer (tramp-get-debug-buffer multi-method
- method user host))
- (goto-char (point-max))
- (tramp-insert-with-face
- 'bold (format "$ %s %s\n" copy-program
- (mapconcat 'identity argl " ")))))
- (unless (equal 0
- (apply #'call-process
- copy-program nil trampbuf nil argl))
- (pop-to-buffer trampbuf)
- (error
- "Cannot write region to file `%s', command `%s' failed"
- filename copy-program))
- (tramp-message-for-buffer
- multi-method method user host
- 6 "Transferring file using `%s'...done"
- copy-program)))
+ (cond ((tramp-method-out-of-band-p multi-method method user host)
+ ;; `copy-file' handles out-of-band methods
+ (copy-file tmpfil filename t t))
+
((and rem-enc rem-dec)
;; Use inline file transfer
(let ((tmpbuf (get-buffer-create " *tramp file transfer*")))
(progn
(tramp-message-for-buffer
multi-method method user host
- 6 "Encoding region using function...")
+ 6 "Encoding region using function `%s'..."
+ (symbol-name loc-enc))
(insert-file-contents-literally tmpfil)
;; CCC. The following `let' is a workaround for
;; the base64.el that comes with pgnus-0.84. If
;; shouldn't have partial tramp file name syntax. Maybe another variable should
;; be introduced overwriting this check in such cases. Or we change tramp
;; file name syntax in order to avoid ambiguities, like in XEmacs ...
-;; In case of XEmacs it can be always true (and wouldn't be necessary).
+;; In case of non unified file names it can be always true (and wouldn't be
+;; necessary, because there are different regexp).
(defun tramp-completion-mode (file)
"Checks whether method / user name / host name completion is active."
(cond
- ((featurep 'xemacs) t)
+ ((not tramp-unified-filenames) t)
((string-match "^/.*:.*:$" file) nil)
((string-match
(concat tramp-prefix-regexp
file)
(member (match-string 1 file) (mapcar 'car tramp-methods)))
((or (equal last-input-event 'tab)
+ ;; Emacs
(and (integerp last-input-event)
(not (event-modifiers last-input-event))
(or (char-equal last-input-event ?\?)
(char-equal last-input-event ?\t) ; handled by 'tab already?
- (char-equal last-input-event ?\ ))))
+ (char-equal last-input-event ?\ )))
+ ;; XEmacs
+ (and (featurep 'xemacs)
+ (not (event-modifiers last-input-event))
+ (or (char-equal
+ (funcall 'event-to-character last-input-event) ?\?)
+ (char-equal
+ (funcall 'event-to-character last-input-event) ?\t)
+ (char-equal
+ (funcall 'event-to-character last-input-event) ?\ ))))
t)))
(defun tramp-completion-handle-file-exists-p (filename)
(forward-line 1))
result))
+(defun tramp-parse-shostkeys (dirname)
+ "Return a list of (user host) tuples allowed to access.
+User is always nil."
+
+ (let ((regexp (concat "^key_[0-9]+_\\(" tramp-host-regexp "\\)\\.pub$"))
+ (files (when (file-directory-p dirname) (directory-files dirname)))
+ result)
+
+ (while files
+ (when (string-match regexp (car files))
+ (push (list nil (match-string 1 (car files))) result))
+ (setq files (cdr files)))
+ result))
+
+(defun tramp-parse-sknownhosts (dirname)
+ "Return a list of (user host) tuples allowed to access.
+User is always nil."
+
+ (let ((regexp (concat "^\\(" tramp-host-regexp
+ "\\)\\.ssh-\\(dss\\|rsa\\)\\.pub$"))
+ (files (when (file-directory-p dirname) (directory-files dirname)))
+ result)
+
+ (while files
+ (when (string-match regexp (car files))
+ (push (list nil (match-string 1 (car files))) result))
+ (setq files (cdr files)))
+ result))
+
(defun tramp-parse-hosts (filename)
"Return a list of (user host) tuples allowed to access.
User is always nil."
(or switch "")
(tramp-shell-quote-argument localname2))))))
+(defun tramp-touch (file time)
+ "Set the last-modified timestamp of the given file.
+TIME is an Emacs internal time value as returned by `current-time'."
+ (let ((touch-time (format-time-string "%Y%m%d%H%M.%S" time)))
+ (with-parsed-tramp-file-name file nil
+ (let ((buf (tramp-get-buffer multi-method method user host)))
+ (unless (zerop (tramp-send-command-and-check
+ multi-method method user host
+ (format "touch -t %s %s"
+ touch-time
+ localname)))
+ (pop-to-buffer buf)
+ (error "tramp-touch: touch failed, see buffer `%s' for details"
+ buf))))))
+
(defun tramp-buffer-name (multi-method method user host)
"A name for the connection buffer for USER at HOST using METHOD."
(if multi-method
(tramp-buffer-name-multi-method "tramp" multi-method method user host)
(let ((method (tramp-find-method multi-method method user host)))
(if user
- (format "*tramp/%s %s@%s*" method user host))
- (format "*tramp/%s %s*" method host))))
+ (format "*tramp/%s %s@%s*" method user host)
+ (format "*tramp/%s %s*" method host)))))
(defun tramp-buffer-name-multi-method (prefix multi-method method user host)
"A name for the multi method connection buffer.
(defun tramp-action-password (p multi-method method user host)
"Query the user for a password."
(let ((pw-prompt (match-string 0)))
- (when (tramp-method-out-of-band-p multi-method method user host)
- (kill-process (get-buffer-process (current-buffer)))
- (error (concat "Out of band method `%s' not applicable "
- "for remote shell asking for a password")
- method))
(tramp-message 9 "Sending password")
(tramp-enter-password p pw-prompt)))
p multi-method method user host actions)
nil)))
(unless (eq exit 'ok)
+ (tramp-clear-passwd user host)
(error "Login failed"))))
;; For multi-actions.
(tramp-process-one-multi-action p method user host actions)
nil)))
(unless (eq exit 'ok)
+ (tramp-clear-passwd user host)
(error "Login failed"))))
;; Functions to execute when we have seen the remote shell prompt but
;; The following should be changed. We need a more general
;; mechanism to parse extra host args.
(when (string-match "\\([^#]*\\)#\\(.*\\)" host)
- (setq login-args (cons "-p" (cons (match-string 2 host) rsh-args)))
+ (setq login-args (cons "-p" (cons (match-string 2 host) login-args)))
(setq host (match-string 1 host)))
(setenv "TERM" tramp-terminal-type)
(let* ((default-directory (tramp-temporary-file-directory))
" -e '" tramp-perl-file-attributes "' $1 $2 2>/dev/null\n"
"}"))
(tramp-wait-for-output)
- (unless (tramp-get-method-parameter
- multi-method
- (tramp-find-method multi-method method user host)
- user host 'tramp-copy-program)
+ (unless (tramp-method-out-of-band-p multi-method method user host)
(tramp-message 5 "Sending the Perl `mime-encode' implementations.")
(tramp-send-string
multi-method method user host
(tramp-set-connection-property "ln" ln multi-method method user host)))
(erase-buffer)
;; Find the right encoding/decoding commands to use.
- (unless (tramp-get-method-parameter
- multi-method
- (tramp-find-method multi-method method user host)
- user host 'tramp-copy-program)
+ (unless (tramp-method-out-of-band-p multi-method method user host)
(tramp-find-inline-encoding multi-method method user host))
;; If encoding/decoding command are given, test to see if they work.
;; CCC: Maybe it would be useful to run the encoder both locally and
(unless (and p (processp p) (memq (process-status p) '(run open)))
(when (and p (processp p))
(delete-process p))
- (funcall (tramp-get-method-parameter
- multi-method
- (tramp-find-method multi-method method user host)
- user host 'tramp-connection-function)
- multi-method method user host))))
+ (let ((process-connection-type tramp-process-connection-type))
+ (funcall (tramp-get-method-parameter
+ multi-method
+ (tramp-find-method multi-method method user host)
+ user host 'tramp-connection-function)
+ multi-method method user host)))))
(defun tramp-send-command
(multi-method method user host command &optional noerase neveropen)
(defun tramp-read-passwd (prompt)
"Read a password from user (compat function).
-Invokes `read-passwd' if that is defined, else `ange-ftp-read-passwd'."
- (apply
- (if (fboundp 'read-passwd) #'read-passwd #'ange-ftp-read-passwd)
- (list prompt)))
+Invokes `password-read' if available, `read-passwd' else."
+ (if (functionp 'password-read)
+ (let* ((user (or tramp-current-user (user-login-name)))
+ (host (or tramp-current-host (system-name)))
+ (key (concat user "@" host))
+ (password (apply #'password-read (list prompt key))))
+ (apply #'password-cache-add (list key password))
+ password)
+ (read-passwd prompt)))
+
+(defun tramp-clear-passwd (&optional user host)
+ "Clear password cache for connection related to current-buffer."
+ (interactive)
+ (let ((filename (or buffer-file-name list-buffers-directory "")))
+ (when (and (functionp 'password-cache-remove)
+ (or (and user host) (tramp-tramp-file-p filename)))
+ (let* ((v (when (tramp-tramp-file-p filename)
+ (tramp-dissect-file-name filename)))
+ (luser (or user (tramp-file-name-user v) (user-login-name)))
+ (lhost (or host (tramp-file-name-host v) (system-name)))
+ (key (concat luser "@" lhost)))
+ (apply #'password-cache-remove (list key))))))
(defun tramp-time-diff (t1 t2)
"Return the difference between the two times, in seconds.
;;; TODO:
-;; * tramp-copy-keep-date-arg is not used!
;; * Allow putting passwords in the filename.
;; This should be implemented via a general mechanism to add
;; parameters in filenames. There is currently a kludge for
@end macro
@copying
-Copyright @copyright{} 1999, 2000, 2001, 2002, 2003 Free Software
+Copyright @copyright{} 1999, 2000, 2001, 2002, 2003, 2004 Free Software
Foundation, Inc.
@quotation
@end copying
@c Entries for @command{install-info} to use
-@dircategory Emacs
+@dircategory @value{emacs-name}
@direntry
* TRAMP: (tramp). Transparent Remote Access, Multiple Protocol
- Emacs remote file access via rsh and rcp.
+ @value{emacs-name} remote file access via rsh and rcp.
@end direntry
@tex
@end ifset
The latest release of @tramp{} is available for
-@uref{http://savannah.gnu.org/download/tramp/,
+@uref{http://savannah.nongnu.org/download/tramp/,
download}, or you may see @ref{Obtaining @tramp{}} for more details,
including the CVS server details.
-@tramp{} also has a @uref{https://savannah.gnu.org/projects/tramp/,
+@tramp{} also has a @uref{http://savannah.nongnu.org/projects/tramp/,
Savannah Project Page}.
@end ifhtml
There is a mailing list for @tramp{}, available at
@email{tramp-devel@@mail.freesoftware.fsf.org}, and archived at
-@uref{http://www.mail-archive.com/emacs-rcp@@ls6.cs.uni-dortmund.de/} as
-well as the usual Savannah archives.
+@uref{http://savannah.nongnu.org/mail/?group=tramp, Savannah Mail
+Archive}.
+@ifhtml
+Older archives are located at
+@uref{http://sourceforge.net/mailarchive/forum.php?forum=tramp-devel,
+SourceForge Mail Archive} and
+@uref{http://www.mail-archive.com/emacs-rcp@@ls6.cs.uni-dortmund.de/,
+The Mail Archive}.
+@c in HTML output, there's no new paragraph.
+@*@*
+@end ifhtml
@insertcopying
* Default Method:: Selecting a default method.
* Customizing Methods:: Using Non-Standard Methods.
* Customizing Completion:: Selecting config files for user/host name completion.
+* Password caching:: Reusing passwords for several connections.
* Remote Programs:: How @tramp{} finds and uses programs on the remote machine.
* Remote shell setup:: Remote shell setup hints.
* Windows setup hints:: Issues with Cygwin ssh.
at the top.
@noindent
-@uref{http://savannah.gnu.org/projects/tramp/}
+@uref{http://savannah.nongnu.org/projects/tramp/}
@noindent
Or follow the example session below:
@example
] @strong{cd ~/@value{emacs-dir}}
-] @strong{cvs -d:pserver:anoncvs@@subversions.gnu.org:/cvsroot/tramp login}
-
-(Logging in to anoncvs@@subversions.gnu.org)
-CVS password: @strong{(just hit RET here)}
-@dots{}
-
-] @strong{cvs -z3 -d:pserver:anoncvs@@subversions.gnu.org:/cvsroot/tramp co tramp}
+] @strong{export CVS_RSH="ssh"}
+] @strong{cvs -z3 -d:ext:anoncvs@@savannah.nongnu.org:/cvsroot/tramp co tramp}
@end example
@noindent
@example
] @strong{cd ~/@value{emacs-dir}/tramp}
+] @strong{export CVS_RSH="ssh"}
] @strong{cvs update -d}
@end example
is right for them.
* Customizing Methods:: Using Non-Standard Methods.
* Customizing Completion:: Selecting config files for user/host name completion.
+* Password caching:: Reusing passwords for several connections.
* Remote Programs:: How @tramp{} finds and uses programs on the remote machine.
* Remote shell setup:: Remote shell setup hints.
* Windows setup hints:: Issues with Cygwin ssh.
hosts, see below.)
These methods depend on the existence of a suitable encoding and
-decoding command on remote machine. Locally, @tramp{} may be able to use
-features of Emacs to decode and encode the files or it may require
-access to external commands to perform that task.
+decoding command on remote machine. Locally, @tramp{} may be able to
+use features of @value{emacs-name} to decode and encode the files or
+it may require access to external commands to perform that task.
@cindex uuencode
@cindex mimencode
in without such questions.
This is also useful for Windows users where @command{ssh}, when
-invoked from an Emacs buffer, tells them that it is not allocating a
-pseudo tty. When this happens, the login shell is wont to not print
-any shell prompt, which confuses @tramp{} mightily. For reasons
-unknown, some Windows ports for @command{ssh} (maybe the Cygwin one)
-require the doubled @samp{-t} option.
+invoked from an @value{emacs-name} buffer, tells them that it is not
+allocating a pseudo tty. When this happens, the login shell is wont
+to not print any shell prompt, which confuses @tramp{} mightily. For
+reasons unknown, some Windows ports for @command{ssh} (maybe the
+Cygwin one) require the doubled @samp{-t} option.
This supports the @samp{-p} kludge.
with.
This is also useful for Windows users where @command{ssh}, when
-invoked from an Emacs buffer, tells them that it is not allocating a
-pseudo tty. When this happens, the login shell is wont to not print
-any shell prompt, which confuses @tramp{} mightily. Maybe this
-applies to the Cygwin port of SSH.
+invoked from an @value{emacs-name} buffer, tells them that it is not
+allocating a pseudo tty. When this happens, the login shell is wont
+to not print any shell prompt, which confuses @tramp{} mightily.
+Maybe this applies to the Cygwin port of SSH.
This method supports the @samp{-p} hack.
@cindex method fsh
@cindex fsh method
+
There is no inline method using @command{fsh} as the multiplexing
provided by the program is not very useful in our context. @tramp{}
opens just one connection to the remote host and then keeps it open,
anyway.
-@ifset emacs
@item @option{ftp}
@cindex method ftp
@cindex ftp method
This is not a native @tramp{} method. Instead of, it forwards all
requests to @value{ftp-package-name}.
+@ifset xemacs
+This works only for unified filenames, see @ref{Issues}.
@end ifset
Since authorization is done on share level, you will be prompted
always for a password if you access another share on the same host.
-Due to security reasons, the password is not cached.
+This can be suppressed by @ref{Password caching}.
MS Windows uses for authorization both a user name and a domain name.
Because of this, the @tramp{} syntax has been extended: you can
The @option{smb} method supports the @samp{-p} hack.
-@strong{Please note:} If Emacs runs locally under MS Windows, this
-method isn't available. Instead of, you can use UNC file names like
-@file{//melancholia/daniel$$/.emacs}. The only disadvantage is that
-there's no possibility to specify another user name.
+@strong{Please note:} If @value{emacs-name} runs locally under MS
+Windows, this method isn't available. Instead of, you can use UNC
+file names like @file{//melancholia/daniel$$/.emacs}. The only
+disadvantage is that there's no possibility to specify another user
+name.
@end table
This function returns the host nicknames defined by @code{Host} entries
in @file{~/.ssh/config} style files.
+@item @code{tramp-parse-shostkeys}
+@findex tramp-parse-shostkeys
+
+SSH2 parsing of directories @file{/etc/ssh2/hostkeys/*} and
+@file{~/ssh2/hostkeys/*}. Hosts are coded in file names
+@file{hostkey_PORTNUMBER_HOST-NAME.pub}. User names are always nil.
+
+@item @code{tramp-parse-sknownhosts}
+@findex tramp-parse-shostkeys
+
+Another SSH2 style parsing of directories like
+@file{/etc/ssh2/knownhosts/*} and @file{~/ssh2/knownhosts/*}. This
+case, hosts names are coded in file names
+@file{HOST-NAME.ALGORITHM.pub}. User names are always nil.
+
@item @code{tramp-parse-hosts}
@findex tramp-parse-hosts
@end defun
+@node Password caching
+@section Reusing passwords for several connections.
+@cindex passwords
+
+Sometimes it is necessary to connect to the same remote host several
+times. Reentering passwords again and again would be annoying, when
+the choosen method does not support access without password prompt
+throught own configuration.
+
+By default, @tramp{} caches the passwords entered by you. They will
+be reused next time if a connection needs them for the same user name
+and host name, independant of the connection method.
+
+@vindex password-cache-expiry
+Passwords are not saved permanently, that means the password caching
+is limited to the lifetime of your @value{emacs-name} session. You
+can influence the lifetime of password caching by customizing the
+variable @code{password-cache-expiry}. The value is the number of
+seconds how long passwords are cached. Setting it to @code{nil}
+disables the expiration.
+
+@findex tramp-clear-passwd
+A password is removed from the cache if a connection isn't established
+successfully. You can remove a password from the cache also by
+executing @kbd{M-x tramp-clear-passwd} in a buffer containing a
+related remote file or directory.
+
+@vindex password-cache
+If you don't like this feature for security reasons, password caching
+can be disabled totally by customizing the variable
+@code{password-cache} (setting it to @code{nil}).
+
+Implementation Note: password caching is based on the package
+password.el in No Gnus. For the time being, it is activated only when
+this package is seen in the @code{load-path} while loading @tramp{}.
+@ifset tramp-inst
+If you don't use No Gnus, you can take password.el from the @tramp{}
+@file{contrib} directory, see @ref{Installation parameters}.
+@end ifset
+It will be activated mandatory once No Gnus has found its way into
+@value{emacs-name}.
+
+
@node Remote Programs
@section How @tramp{} finds and uses programs on the remote machine.
@cindex backup
@vindex backup-directory-alist
-Explaining auto-save is still to do.
-
-Normally, Emacs writes backup files to the same directory as the
-original files, but this behavior can be changed via the variable
-@code{backup-directory-alist}. In connection with @tramp{}, this can
-have unexpected side effects. Suppose that you specify that all backups
-should go to the directory @file{~/.emacs.d/backups/}, and then you edit
-the file @file{/su:root@@localhost:/etc/secretfile}. The effect is that
-the backup file will be owned by you and not by root, thus possibly
-enabling others to see it even if they were not intended to see it.
+Normally, @value{emacs-name} writes backup files to the same directory
+as the original files, but this behavior can be changed via the
+variable @code{backup-directory-alist}. In connection with @tramp{},
+this can have unexpected side effects. Suppose that you specify that
+all backups should go to the directory @file{~/.emacs.d/backups/}, and
+then you edit the file @file{/su:root@@localhost:/etc/secretfile}.
+The effect is that the backup file will be owned by you and not by
+root, thus possibly enabling others to see it even if they were not
+intended to see it.
When @code{backup-directory-alist} is nil (the default), such problems
do not occur.
(cons tramp-file-name-regexp nil))
@end lisp
+The same problem can happen with auto-saving files.
+@ifset emacs
+Since @value{emacs-name} 21, the variable
+@code{auto-save-file-name-transforms} keeps information, on which
+directory an auto-saved file should go. By default, it is initialized
+for @tramp{} files to the local temporary directory.
+
+On some versions of @value{emacs-name}, namely the version built for
+Debian Linux, the variable @code{auto-save-file-name-transforms}
+contains the directory where @value{emacs-name} was built. A
+workaround is to manually set the variable to a sane value.
+
+If auto-saved files should go into the same directory as the original
+files, @code{auto-save-file-name-transforms} should be set to nil.
+
+Another possibility is to set the variable
+@code{tramp-auto-save-directory} to a proper value.
+@end ifset
+@ifset xemacs
+For this purpose you can set the variable
+@code{tramp-auto-save-directory} to a proper value.
+@end ifset
+
@node Windows setup hints
@section Issues with Cygwin ssh
@cindex method scpx with Cygwin
@cindex scpx method with Cygwin
If you wish to use the @code{scpx} connection method, then you might
-have the problem that Emacs calls @code{scp} with a Windows filename
-such as @code{c:/foo}. The Cygwin version of @code{scp} does not know
-about Windows filenames and interprets this as a remote filename on the
-host @code{c}.
+have the problem that @value{emacs-name} calls @code{scp} with a
+Windows filename such as @code{c:/foo}. The Cygwin version of
+@code{scp} does not know about Windows filenames and interprets this
+as a remote filename on the host @code{c}.
One possible workaround is to write a wrapper script for @code{scp}
which converts the Windows filename to a Cygwinized filename.
-I guess that another workaround is to run Emacs under Cygwin, or to run
-a Cygwinized Emacs.
+I guess that another workaround is to run @value{emacs-name} under
+Cygwin, or to run a Cygwinized @value{emacs-name}.
@cindex Cygwin and ssh-agent
-@cindex SSH_AUTH_SOCK and Emacs on Windows
+@cindex SSH_AUTH_SOCK and @value{emacs-name} on Windows
If you want to use either @code{ssh} based method on Windows, then you
might encounter problems with @code{ssh-agent}. Using this program,
you can avoid typing the pass-phrase every time you log in (and the
@code{scpx} method more or less requires you to use @code{ssh-agent}
because it does not allow you to type a password or pass-phrase).
-However, if you start Emacs from a desktop shortcut, then the
-environment variable @code{SSH_AUTH_SOCK} is not set and so Emacs and
-thus @tramp{} and thus @code{ssh} and @code{scp} started from @tramp{}
-cannot communicate with @code{ssh-agent}. It works better to start
-Emacs from the shell.
+However, if you start @value{emacs-name} from a desktop shortcut, then
+the environment variable @code{SSH_AUTH_SOCK} is not set and so
+@value{emacs-name} and thus @tramp{} and thus @code{ssh} and
+@code{scp} started from @tramp{} cannot communicate with
+@code{ssh-agent}. It works better to start @value{emacs-name} from
+the shell.
If anyone knows how to start @code{ssh-agent} under Windows in such a
way that desktop shortcuts can profit, please holler. I don't really
by the @value{ftp-package-name} package.
@cindex type-ahead
-Something that might happen which surprises you is that Emacs
-remembers all your keystrokes, so if you see a password prompt from
-Emacs, say, and hit @kbd{@key{RET}} twice instead of once, then the
-second keystroke will be processed by Emacs after @tramp{} has done
-its thing. Why, this type-ahead is normal behavior, you say. Right
-you are, but be aware that opening a remote file might take quite a
-while, maybe half a minute when a connection needs to be opened.
-Maybe after half a minute you have already forgotten that you hit that
-key!
+Something that might happen which surprises you is that
+@value{emacs-name} remembers all your keystrokes, so if you see a
+password prompt from @value{emacs-name}, say, and hit @kbd{@key{RET}}
+twice instead of once, then the second keystroke will be processed by
+@value{emacs-name} after @tramp{} has done its thing. Why, this
+type-ahead is normal behavior, you say. Right you are, but be aware
+that opening a remote file might take quite a while, maybe half a
+minute when a connection needs to be opened. Maybe after half a
+minute you have already forgotten that you hit that key!
@menu
* Filename Syntax:: @tramp{} filename conventions.
The syntax of multi-hop file names is necessarily slightly different
than the syntax of other @tramp{} file names. Here's an example
-multi-hop file name, first in Emacs syntax and then in XEmacs syntax:
+multi-hop file name:
@example
@value{tramp-prefix}multi@value{tramp-postfix-single-hop}rsh@value{tramp-postfix-multi-hop}out@@gate@value{tramp-postfix-single-hop}telnet@value{tramp-postfix-multi-hop}kai@@real.host@value{tramp-postfix}/path/to.file
There is also a Savannah project page.
@noindent
-@uref{https://savannah.gnu.org/projects/tramp/}
+@uref{http://savannah.nongnu.org/projects/tramp/}
@item
Which systems does it work on?
@file{tramp.el}. I don't think anybody has really tried it on Emacs 19.
The package was intended to work on Unix, and it really expects a
-Unix-like system on the remote end, but some people seemed to have some
-success getting it to work on NT Emacs.
+Unix-like system on the remote end (except the @option{smb} method),
+but some people seemed to have some success getting it to work on NT
+Emacs.
There is some informations on @tramp{} on NT at the following URL;
many thanks to Joe Stoy for providing the information:
@item
How can I get notified when @tramp{} file transfers are complete?
-The following snippet can be put in your @file{~/.emacs} file. It makes
-Emacs beep after reading from or writing to the remote host.
+The following snippet can be put in your @file{~/.emacs} file. It
+makes @value{emacs-name} beep after reading from or writing to the
+remote host.
@lisp
(defadvice tramp-handle-write-region
@node Remote File Ownership
@subsection How VC determines who owns a workfile
-Emacs provides the @code{user-full-name} function to return the login name
-of the current user as well as mapping from arbitrary user id values
-back to login names. The VC code uses this functionality to map from the
-uid of the owner of a workfile to the login name in some circumstances.
+@value{emacs-name} provides the @code{user-full-name} function to
+return the login name of the current user as well as mapping from
+arbitrary user id values back to login names. The VC code uses this
+functionality to map from the uid of the owner of a workfile to the
+login name in some circumstances.
This will not, for obvious reasons, work if the remote system has a
different set of logins. As such, it is necessary to delegate to the
installed from the start. If the filenames were unified, @tramp{}
would have to be installed from the start, too.
+@ifset xemacs
+@strong{Note:} If you'ld like to use a similar syntax like
+@value{ftp-package-name}, you need the following settings in your init
+file:
+
+@lisp
+(setq tramp-unified-filenames t)
+(require 'tramp)
+@end lisp
+
+The autoload of the @value{emacs-name} @tramp{} package must be
+disabled. This can be achieved by setting file permissions @code{000}
+to the files @file{.../xemacs-packages/lisp/tramp/auto-autoloads.el*}.
+
+In case of unified filenames, all @value{emacs-name} download sites
+are added to @code{tramp-default-method-alist} with default method
+@code{ftp} @xref{Default Method}. These settings shouldn't be touched
+for proper working of the @value{emacs-name} package system.
+
+The syntax for unified filenames is described in the @tramp{} manual
+for @value{emacs-other-name}.
+@end ifset
+
@end itemize
@node Concept Index
@c ** Use `filename' resp. `file name' consistently.
@c ** Use `host' resp. `machine' consistently.
@c ** Consistent small or capitalized words especially in menues.
-
-@ignore
- arch-tag: f96dd66e-6dd3-4c92-8d77-9c56205ba808
-@end ignore