Sync with Tramp 2.2.6-pre.
* net/tramp-cache.el (tramp-dump-connection-properties): Let-bind `print-length' and `print-level' to nil, in order to avoid truncation. Reported by Christopher Schmidt <christopher@ristopher.com>. * net/tramp-cmds.el (tramp-cleanup-connection): Delete also process. * net/tramp-compat.el (tramp-compat-condition-case-unless-debug): New defmacro. (tramp-compat-copy-directory): Add optional argument COPY-CONTENTS. It is not handled yet. * net/tramp-ftp.el (tramp-disable-ange-ftp): Fix docstring. (tramp-ftp-file-name-p): Simplify. * net/tramp-gvfs.el (tramp-gvfs-handle-expand-file-name): * net/tramp-gw.el (tramp-gw-open-connection): Add hop to connection vector. * net/tramp-sh.el (tramp-copy-size-limit): Fix docstring. (tramp-methods): Do not use `tramp-password-end-of-line'. (tramp-completion-function-alist-putty): Handle UNIX case. (tramp-remote-path): Add "/opt/bin", "/opt/sbin" and "/opt/local/bin". (tramp-do-file-attributes-with-stat) (tramp-do-directory-files-and-attributes-with-stat) Return uid and gid as real numbers. They could run out of integer range on cygwin. (tramp-do-copy-or-rename-file-out-of-band): Better trace format. (tramp-sh-handle-expand-file-name): Handle hops. (tramp-open-connection-setup-interactive-shell): Use `tramp-cleanup'. Move check for busyboxes ... (tramp-find-shell): ... here. Simplify implementation. Set "remote-shell" property also for alternative shells. (tramp-remote-coding-commands): Check "test -c /dev/stdout". If failing, a regular file would be written otherwise. Reported by Dmitry Kurochkin <dmitry.kurochkin@gmail.com>. (tramp-find-inline-encoding): Cache the coding commands in the process cache. Apply test command on the remote side, if defined. (tramp-find-inline-compress): Cache the compress commands in the process cache. (tramp-compute-multi-hops): Save `tramp-default-proxies-alist' when requested. Handle hops. (tramp-current-connection): New defvar. (tramp-maybe-open-connection): Use `tramp-cleanup'. Throw `suppress', if there was a failed connection shortly before. Handle user interrupt. (Bug#10187) (tramp-get-inline-compress, tramp-get-inline-coding): Read connection properties from the process cache. * net/tramp-smb.el (tramp-smb-server-version) (tramp-smb-wrong-passwd-regexp, tramp-smb-actions-with-tar): New defconsts. (tramp-smb-prompt): Extend for powershell prompt. (tramp-smb-file-name-handler-alist): Add handlers for `process-file', `shell-command' and `start-file-process'. (tramp-smb-winexe-program, tramp-smb-winexe-shell-command) (tramp-smb-winexe-shell-command-switch): New defcustoms. (tramp-smb-file-name-p): Simplify. (tramp-smb-action-with-tar, tramp-smb-handle-process-file) (tramp-smb-kill-winexe-function, tramp-smb-call-winexe) (tramp-smb-shell-quote-argument): New defuns. (tramp-smb-handle-copy-directory): Add COPY-CONTENTS argument. Implement using "tar". By this, time-stamps are preserved. (tramp-smb-handle-copy-file): Handle also the case of directories. (tramp-smb-do-file-attributes-with-stat) (tramp-smb-get-file-entries, tramp-smb-get-cifs-capabilities): Use `tramp-get-connection-buffer'). (tramp-smb-handle-rename-file): Use "rename", when source and target are on the same share. (tramp-smb-maybe-open-connection): Handle wrong passwords. Use `tramp-smb-server-version'. (tramp-smb-wait-for-output): Remove prompt. * net/tramp.el (top): Require 'cl. (tramp-methods, tramp-rsh-end-of-line): Remove `tramp-password-end-of-line' from docstring. (tramp-save-ad-hoc-proxies): New defcustom. (tramp-completion-function-alist): Adapt docstring. (tramp-default-password-end-of-line): Remove defcustom. (tramp-shell-prompt-pattern): Allow "[]" style prompts. (Bug#11065) (tramp-user-regexp, tramp-file-name-regexp-unified) (tramp-file-name-regexp-url): Extend regexp by hop separator. (tramp-postfix-hop-format, tramp-postfix-hop-regexp) (tramp-remote-file-name-spec-regexp): New defconst. (tramp-file-name-structure): Extend structure for hops. (tramp-get-method-parameter): Move up. (tramp-file-name-p, tramp-dissect-file-name) (with-parsed-tramp-file-name): Handle hops. (tramp-file-name-hop): New defun. (tramp-make-tramp-file-name): New optional arg HOP. (tramp-message-show-progress-reporter-message): New defvar. (tramp-with-progress-reporter): Use it. We cannot use `tramp-message-show-message' here, because this suppresses also error buffers. (tramp-error-with-buffer): Suppress buffer view, if `tramp-message-show-message' is nil. Use `tramp-get-connection-buffer'. (tramp-cleanup): New defun. (tramp-rfn-eshadow-update-overlay): Let-bind `non-essential' to `t'. (tramp-file-name-handler): If `debug-on-error' is set, propagate an error unchanged. (tramp-completion-handle-file-name-all-completions): Handle hops. Fix an error when called from ido. (tramp-completion-dissect-file-name): Use better local variable name. Add hop to the vector. (tramp-handle-insert-file-contents): Use progress-reporter for the whole scenario. (tramp-action-password): Let-bind `enable-recursive-minibuffers' to `t'. (tramp-check-for-regexp): Simplify search. (tramp-enter-password): Remove it. Move implementation ... (tramp-action-password): ... here. (tramp-mode-string-to-int, tramp-local-host-p) (tramp-make-tramp-temp-file, tramp-read-passwd) (tramp-clear-passwd, tramp-time-less-p, tramp-time-diff): Set tramp-autoload cookie. * net/trampver.el: Update release number. * net/tramp.el (tramp-set-completion-function): Fix docstring. (tramp-parse-group, tramp-parse-file) (tramp-parse-shostkeys-sknownhosts): New defuns. (tramp-parse-rhosts, tramp-parse-rhosts-group, tramp-parse-shosts) (tramp-parse-shosts-group, tramp-parse-sconfig) (tramp-parse-sconfig-group, tramp-parse-shostkeys) (tramp-parse-sknownhosts, tramp-parse-hosts) (tramp-parse-hosts-group, tramp-parse-passwd, tramp-parse-netrc): Use them. (tramp-parse-passwd-group, tramp-parse-netrc-group) (tramp-parse-putty-group): Don't narrow. (tramp-parse-putty): Make a loop. (tramp-file-name-handler): Catch the `suppress' signal.
This commit is contained in:
parent
72834e10a6
commit
2fe4b1254d
11 changed files with 1211 additions and 648 deletions
145
lisp/ChangeLog
145
lisp/ChangeLog
|
@ -1,3 +1,142 @@
|
|||
2012-06-11 Michael Albinus <michael.albinus@gmx.de>
|
||||
|
||||
Sync with Tramp 2.2.6-pre.
|
||||
|
||||
* net/tramp-cache.el (tramp-dump-connection-properties): Let-bind
|
||||
`print-length' and `print-level' to nil, in order to avoid
|
||||
truncation. Reported by Christopher Schmidt
|
||||
<christopher@ristopher.com>.
|
||||
|
||||
* net/tramp-cmds.el (tramp-cleanup-connection): Delete also process.
|
||||
|
||||
* net/tramp-compat.el (tramp-compat-condition-case-unless-debug):
|
||||
New defmacro.
|
||||
(tramp-compat-copy-directory): Add optional argument
|
||||
COPY-CONTENTS. It is not handled yet.
|
||||
|
||||
* net/tramp-ftp.el (tramp-disable-ange-ftp): Fix docstring.
|
||||
(tramp-ftp-file-name-p): Simplify.
|
||||
|
||||
* net/tramp-gvfs.el (tramp-gvfs-handle-expand-file-name):
|
||||
* net/tramp-gw.el (tramp-gw-open-connection): Add hop to
|
||||
connection vector.
|
||||
|
||||
* net/tramp-sh.el (tramp-copy-size-limit): Fix docstring.
|
||||
(tramp-methods): Do not use `tramp-password-end-of-line'.
|
||||
(tramp-completion-function-alist-putty): Handle UNIX case.
|
||||
(tramp-remote-path): Add "/opt/bin", "/opt/sbin" and "/opt/local/bin".
|
||||
(tramp-do-file-attributes-with-stat)
|
||||
(tramp-do-directory-files-and-attributes-with-stat) Return uid and
|
||||
gid as real numbers. They could run out of integer range on cygwin.
|
||||
(tramp-do-copy-or-rename-file-out-of-band): Better trace format.
|
||||
(tramp-sh-handle-expand-file-name): Handle hops.
|
||||
(tramp-open-connection-setup-interactive-shell): Use
|
||||
`tramp-cleanup'. Move check for busyboxes ...
|
||||
(tramp-find-shell): ... here. Simplify implementation. Set
|
||||
"remote-shell" property also for alternative shells.
|
||||
(tramp-remote-coding-commands): Check "test -c /dev/stdout". If
|
||||
failing, a regular file would be written otherwise. Reported by
|
||||
Dmitry Kurochkin <dmitry.kurochkin@gmail.com>.
|
||||
(tramp-find-inline-encoding): Cache the coding commands in the
|
||||
process cache. Apply test command on the remote side, if defined.
|
||||
(tramp-find-inline-compress): Cache the compress commands in the
|
||||
process cache.
|
||||
(tramp-compute-multi-hops): Save `tramp-default-proxies-alist'
|
||||
when requested. Handle hops.
|
||||
(tramp-current-connection): New defvar.
|
||||
(tramp-maybe-open-connection): Use `tramp-cleanup'. Throw
|
||||
`suppress', if there was a failed connection shortly before.
|
||||
Handle user interrupt. (Bug#10187)
|
||||
(tramp-get-inline-compress, tramp-get-inline-coding): Read
|
||||
connection properties from the process cache.
|
||||
|
||||
* net/tramp-smb.el (tramp-smb-server-version)
|
||||
(tramp-smb-wrong-passwd-regexp, tramp-smb-actions-with-tar): New
|
||||
defconsts.
|
||||
(tramp-smb-prompt): Extend for powershell prompt.
|
||||
(tramp-smb-file-name-handler-alist): Add handlers for
|
||||
`process-file', `shell-command' and `start-file-process'.
|
||||
(tramp-smb-winexe-program, tramp-smb-winexe-shell-command)
|
||||
(tramp-smb-winexe-shell-command-switch): New defcustoms.
|
||||
(tramp-smb-file-name-p): Simplify.
|
||||
(tramp-smb-action-with-tar, tramp-smb-handle-process-file)
|
||||
(tramp-smb-kill-winexe-function, tramp-smb-call-winexe)
|
||||
(tramp-smb-shell-quote-argument): New defuns.
|
||||
(tramp-smb-handle-copy-directory): Add COPY-CONTENTS argument.
|
||||
Implement using "tar". By this, time-stamps are preserved.
|
||||
(tramp-smb-handle-copy-file): Handle also the case of directories.
|
||||
(tramp-smb-do-file-attributes-with-stat)
|
||||
(tramp-smb-get-file-entries, tramp-smb-get-cifs-capabilities): Use
|
||||
`tramp-get-connection-buffer').
|
||||
(tramp-smb-handle-rename-file): Use "rename", when source and
|
||||
target are on the same share.
|
||||
(tramp-smb-maybe-open-connection): Handle wrong passwords. Use
|
||||
`tramp-smb-server-version'.
|
||||
(tramp-smb-wait-for-output): Remove prompt.
|
||||
|
||||
* net/tramp.el (top): Require 'cl.
|
||||
(tramp-methods, tramp-rsh-end-of-line): Remove
|
||||
`tramp-password-end-of-line' from docstring.
|
||||
(tramp-save-ad-hoc-proxies): New defcustom.
|
||||
(tramp-completion-function-alist): Adapt docstring.
|
||||
(tramp-default-password-end-of-line): Remove defcustom.
|
||||
(tramp-shell-prompt-pattern): Allow "[]" style prompts. (Bug#11065)
|
||||
(tramp-user-regexp, tramp-file-name-regexp-unified)
|
||||
(tramp-file-name-regexp-url): Extend regexp by hop separator.
|
||||
(tramp-postfix-hop-format, tramp-postfix-hop-regexp)
|
||||
(tramp-remote-file-name-spec-regexp): New defconst.
|
||||
(tramp-file-name-structure): Extend structure for hops.
|
||||
(tramp-get-method-parameter): Move up.
|
||||
(tramp-file-name-p, tramp-dissect-file-name)
|
||||
(with-parsed-tramp-file-name): Handle hops.
|
||||
(tramp-file-name-hop): New defun.
|
||||
(tramp-make-tramp-file-name): New optional arg HOP.
|
||||
(tramp-message-show-progress-reporter-message): New defvar.
|
||||
(tramp-with-progress-reporter): Use it. We cannot use
|
||||
`tramp-message-show-message' here, because this suppresses also
|
||||
error buffers.
|
||||
(tramp-error-with-buffer): Suppress buffer view, if
|
||||
`tramp-message-show-message' is nil. Use
|
||||
`tramp-get-connection-buffer'.
|
||||
(tramp-cleanup): New defun.
|
||||
(tramp-rfn-eshadow-update-overlay): Let-bind `non-essential' to `t'.
|
||||
(tramp-file-name-handler): If `debug-on-error' is set, propagate
|
||||
an error unchanged.
|
||||
(tramp-completion-handle-file-name-all-completions): Handle hops.
|
||||
Fix an error when called from ido.
|
||||
(tramp-completion-dissect-file-name): Use better local variable
|
||||
name. Add hop to the vector.
|
||||
(tramp-handle-insert-file-contents): Use progress-reporter for the
|
||||
whole scenario.
|
||||
(tramp-action-password): Let-bind `enable-recursive-minibuffers'
|
||||
to `t'.
|
||||
(tramp-check-for-regexp): Simplify search.
|
||||
(tramp-enter-password): Remove it. Move implementation ...
|
||||
(tramp-action-password): ... here.
|
||||
(tramp-mode-string-to-int, tramp-local-host-p)
|
||||
(tramp-make-tramp-temp-file, tramp-read-passwd)
|
||||
(tramp-clear-passwd, tramp-time-less-p, tramp-time-diff): Set
|
||||
tramp-autoload cookie.
|
||||
|
||||
* net/trampver.el: Update release number.
|
||||
|
||||
2012-06-11 Thierry Volpiatto <thierry.volpiatto@gmail.com>
|
||||
Michael Albinus <michael.albinus@gmx.de>
|
||||
|
||||
* net/tramp.el (tramp-set-completion-function): Fix docstring.
|
||||
(tramp-parse-group, tramp-parse-file)
|
||||
(tramp-parse-shostkeys-sknownhosts): New defuns.
|
||||
(tramp-parse-rhosts, tramp-parse-rhosts-group, tramp-parse-shosts)
|
||||
(tramp-parse-shosts-group, tramp-parse-sconfig)
|
||||
(tramp-parse-sconfig-group, tramp-parse-shostkeys)
|
||||
(tramp-parse-sknownhosts, tramp-parse-hosts)
|
||||
(tramp-parse-hosts-group, tramp-parse-passwd, tramp-parse-netrc):
|
||||
Use them.
|
||||
(tramp-parse-passwd-group, tramp-parse-netrc-group)
|
||||
(tramp-parse-putty-group): Don't narrow.
|
||||
(tramp-parse-putty): Make a loop.
|
||||
(tramp-file-name-handler): Catch the `suppress' signal.
|
||||
|
||||
2012-06-11 Chong Yidong <cyd@gnu.org>
|
||||
|
||||
* image.el (imagemagick-register-types): Put the ImageMagick entry
|
||||
|
@ -4884,9 +5023,6 @@
|
|||
|
||||
* net/tramp.el (tramp-action-login): Set connection property "login-as".
|
||||
|
||||
* net/tramp-cache.el (tramp-dump-connection-properties): Do not dump
|
||||
properties, when "login-as" is set.
|
||||
|
||||
* net/tramp-sh.el (tramp-methods): Add user spec to "pscp" and "psftp".
|
||||
(tramp-default-user-alist): Don't add "pscp".
|
||||
(tramp-do-copy-or-rename-file-out-of-band): Use connection
|
||||
|
@ -6211,9 +6347,6 @@
|
|||
|
||||
2011-11-16 Michael Albinus <michael.albinus@gmx.de>
|
||||
|
||||
* net/tramp-cache.el (tramp-flush-file-property): Flush also
|
||||
properties of linked files. (Bug#9879)
|
||||
|
||||
* net/tramp-sh.el (tramp-sh-handle-file-truename): Cache only the
|
||||
local file name.
|
||||
|
||||
|
|
|
@ -328,7 +328,8 @@ KEY identifies the connection, it is either a process or a vector."
|
|||
(not (zerop (hash-table-count tramp-cache-data)))
|
||||
tramp-cache-data-changed
|
||||
(stringp tramp-persistency-file-name))
|
||||
(let ((cache (copy-hash-table tramp-cache-data)))
|
||||
(let ((cache (copy-hash-table tramp-cache-data))
|
||||
print-length print-level)
|
||||
;; Remove temporary data. If there is the key "login-as", we
|
||||
;; don't save either, because all other properties might
|
||||
;; depend on the login name, and we want to give the
|
||||
|
|
|
@ -89,7 +89,9 @@ When called interactively, a Tramp connection has to be selected."
|
|||
(tramp-flush-directory-property vec "")
|
||||
|
||||
;; Flush connection cache.
|
||||
(tramp-flush-connection-property (tramp-get-connection-process vec))
|
||||
(when (processp (tramp-get-connection-process vec))
|
||||
(delete-process (tramp-get-connection-process vec))
|
||||
(tramp-flush-connection-property (tramp-get-connection-process vec)))
|
||||
(tramp-flush-connection-property vec)
|
||||
|
||||
;; Remove buffers.
|
||||
|
|
|
@ -194,6 +194,22 @@
|
|||
"Display MESSAGE temporarily if non-nil while BODY is evaluated."
|
||||
`(progn ,@body)))
|
||||
|
||||
;; `condition-case-unless-debug' is introduced with Emacs 24.
|
||||
(if (fboundp 'condition-case-unless-debug)
|
||||
(defalias 'tramp-compat-condition-case-unless-debug
|
||||
'condition-case-unless-debug)
|
||||
(defmacro tramp-compat-condition-case-unless-debug
|
||||
(var bodyform &rest handlers)
|
||||
"Like `condition-case' except that it does not catch anything when debugging."
|
||||
(declare (debug condition-case) (indent 2))
|
||||
(let ((bodysym (make-symbol "body")))
|
||||
`(let ((,bodysym (lambda () ,bodyform)))
|
||||
(if debug-on-error
|
||||
(funcall ,bodysym)
|
||||
(condition-case ,var
|
||||
(funcall ,bodysym)
|
||||
,@handlers))))))
|
||||
|
||||
;; `font-lock-add-keywords' does not exist in XEmacs.
|
||||
(defun tramp-compat-font-lock-add-keywords (mode keywords &optional how)
|
||||
"Add highlighting KEYWORDS for MODE."
|
||||
|
@ -312,43 +328,49 @@ Not actually used. Use `(format \"%o\" i)' instead?"
|
|||
;; `copy-directory' is a new function in Emacs 23.2. Implementation
|
||||
;; is taken from there.
|
||||
(defun tramp-compat-copy-directory
|
||||
(directory newname &optional keep-time parents)
|
||||
(directory newname &optional keep-time parents copy-contents)
|
||||
"Make a copy of DIRECTORY (compat function)."
|
||||
(if (fboundp 'copy-directory)
|
||||
(tramp-compat-funcall 'copy-directory directory newname keep-time parents)
|
||||
(condition-case nil
|
||||
(tramp-compat-funcall
|
||||
'copy-directory directory newname keep-time parents copy-contents)
|
||||
|
||||
;; If `default-directory' is a remote directory, make sure we find
|
||||
;; its `copy-directory' handler.
|
||||
(let ((handler (or (find-file-name-handler directory 'copy-directory)
|
||||
(find-file-name-handler newname 'copy-directory))))
|
||||
(if handler
|
||||
(funcall handler 'copy-directory directory newname keep-time parents)
|
||||
;; `copy-directory' is either not implemented, or it does not
|
||||
;; support the the COPY-CONTENTS flag. For the time being, we
|
||||
;; ignore COPY-CONTENTS as well.
|
||||
|
||||
;; Compute target name.
|
||||
(setq directory (directory-file-name (expand-file-name directory))
|
||||
newname (directory-file-name (expand-file-name newname)))
|
||||
(if (and (file-directory-p newname)
|
||||
(not (string-equal (file-name-nondirectory directory)
|
||||
(file-name-nondirectory newname))))
|
||||
(setq newname
|
||||
(expand-file-name
|
||||
(file-name-nondirectory directory) newname)))
|
||||
(if (not (file-directory-p newname)) (make-directory newname parents))
|
||||
(error
|
||||
;; If `default-directory' is a remote directory, make sure we
|
||||
;; find its `copy-directory' handler.
|
||||
(let ((handler (or (find-file-name-handler directory 'copy-directory)
|
||||
(find-file-name-handler newname 'copy-directory))))
|
||||
(if handler
|
||||
(funcall handler 'copy-directory directory newname keep-time parents)
|
||||
|
||||
;; Copy recursively.
|
||||
(mapc
|
||||
(lambda (file)
|
||||
(if (file-directory-p file)
|
||||
(tramp-compat-copy-directory file newname keep-time parents)
|
||||
(copy-file file newname t keep-time)))
|
||||
;; We do not want to delete "." and "..".
|
||||
(directory-files
|
||||
directory 'full "^\\([^.]\\|\\.\\([^.]\\|\\..\\)\\).*"))
|
||||
;; Compute target name.
|
||||
(setq directory (directory-file-name (expand-file-name directory))
|
||||
newname (directory-file-name (expand-file-name newname)))
|
||||
(if (and (file-directory-p newname)
|
||||
(not (string-equal (file-name-nondirectory directory)
|
||||
(file-name-nondirectory newname))))
|
||||
(setq newname
|
||||
(expand-file-name
|
||||
(file-name-nondirectory directory) newname)))
|
||||
(if (not (file-directory-p newname)) (make-directory newname parents))
|
||||
|
||||
;; Set directory attributes.
|
||||
(set-file-modes newname (file-modes directory))
|
||||
(if keep-time
|
||||
(set-file-times newname (nth 5 (file-attributes directory))))))))
|
||||
;; Copy recursively.
|
||||
(mapc
|
||||
(lambda (file)
|
||||
(if (file-directory-p file)
|
||||
(tramp-compat-copy-directory file newname keep-time parents)
|
||||
(copy-file file newname t keep-time)))
|
||||
;; We do not want to delete "." and "..".
|
||||
(directory-files
|
||||
directory 'full "^\\([^.]\\|\\.\\([^.]\\|\\..\\)\\).*"))
|
||||
|
||||
;; Set directory attributes.
|
||||
(set-file-modes newname (file-modes directory))
|
||||
(if keep-time
|
||||
(set-file-times newname (nth 5 (file-attributes directory)))))))))
|
||||
|
||||
;; TRASH has been introduced with Emacs 24.1.
|
||||
(defun tramp-compat-delete-file (filename &optional trash)
|
||||
|
|
|
@ -49,9 +49,8 @@
|
|||
(defun tramp-disable-ange-ftp ()
|
||||
"Turn Ange-FTP off.
|
||||
This is useful for unified remoting. See
|
||||
`tramp-file-name-structure-unified' and
|
||||
`tramp-file-name-structure-separate' for details. Requests suitable
|
||||
for Ange-FTP will be forwarded to Ange-FTP. Also see the variables
|
||||
`tramp-file-name-structure' for details. Requests suitable for
|
||||
Ange-FTP will be forwarded to Ange-FTP. Also see the variables
|
||||
`tramp-ftp-method', `tramp-default-method', and
|
||||
`tramp-default-method-alist'.
|
||||
|
||||
|
@ -204,8 +203,8 @@ pass to the OPERATION."
|
|||
;;;###tramp-autoload
|
||||
(defsubst tramp-ftp-file-name-p (filename)
|
||||
"Check if it's a filename that should be forwarded to Ange-FTP."
|
||||
(let ((v (tramp-dissect-file-name filename)))
|
||||
(string= (tramp-file-name-method v) tramp-ftp-method)))
|
||||
(string= (tramp-file-name-method (tramp-dissect-file-name filename))
|
||||
tramp-ftp-method))
|
||||
|
||||
;;;###tramp-autoload
|
||||
(unless (featurep 'xemacs)
|
||||
|
|
|
@ -625,7 +625,7 @@ is no information where to trace the message.")
|
|||
;; If there is a default location, expand tilde.
|
||||
(when (string-match "\\`\\(~\\)\\(/\\|\\'\\)" localname)
|
||||
(save-match-data
|
||||
(tramp-gvfs-maybe-open-connection (vector method user host "/")))
|
||||
(tramp-gvfs-maybe-open-connection (vector method user host "/" hop)))
|
||||
(setq localname
|
||||
(replace-match
|
||||
(tramp-get-file-property v "/" "default-location" "~")
|
||||
|
|
|
@ -154,7 +154,7 @@ instead of the host name declared in TARGET-VEC."
|
|||
(memq (process-status tramp-gw-aux-proc) '(listen)))
|
||||
(let ((aux-vec
|
||||
(vector "aux" (tramp-file-name-user gw-vec)
|
||||
(tramp-file-name-host gw-vec) nil)))
|
||||
(tramp-file-name-host gw-vec) nil nil)))
|
||||
(setq tramp-gw-aux-proc
|
||||
(make-network-process
|
||||
:name (tramp-buffer-name aux-vec) :buffer nil :host 'local
|
||||
|
|
|
@ -51,8 +51,9 @@ If it is nil, no compression at all will be applied."
|
|||
:type '(choice (const nil) integer))
|
||||
|
||||
(defcustom tramp-copy-size-limit 10240
|
||||
"The maximum file size where inline copying is preferred over an out-of-the-band copy.
|
||||
If it is nil, inline out-of-the-band copy will be used without a check."
|
||||
"The maximum file size where inline copying is preferred over an \
|
||||
out-of-the-band copy.
|
||||
If it is nil, out-of-the-band copy will be used without a check."
|
||||
:group 'tramp
|
||||
:type '(choice (const nil) integer))
|
||||
|
||||
|
@ -347,7 +348,6 @@ detected as prompt when being sent on echoing hosts, therefore.")
|
|||
(tramp-login-args (("-l" "%u") ("-P" "%p") ("-ssh") ("%h")))
|
||||
(tramp-remote-shell "/bin/sh")
|
||||
(tramp-remote-shell-args ("-c"))
|
||||
(tramp-password-end-of-line "xy") ;see docstring for "xy"
|
||||
(tramp-default-port 22)))
|
||||
;;;###tramp-autoload
|
||||
(add-to-list 'tramp-methods
|
||||
|
@ -356,7 +356,6 @@ detected as prompt when being sent on echoing hosts, therefore.")
|
|||
(tramp-login-args (("-l" "%u") ("-P" "%p") ("-1" "-ssh") ("%h")))
|
||||
(tramp-remote-shell "/bin/sh")
|
||||
(tramp-remote-shell-args ("-c"))
|
||||
(tramp-password-end-of-line "xy") ;see docstring for "xy"
|
||||
(tramp-default-port 22)))
|
||||
;;;###tramp-autoload
|
||||
(add-to-list 'tramp-methods
|
||||
|
@ -384,7 +383,6 @@ detected as prompt when being sent on echoing hosts, therefore.")
|
|||
("-q") ("-r")))
|
||||
(tramp-copy-keep-date t)
|
||||
(tramp-copy-recursive t)
|
||||
(tramp-password-end-of-line "xy") ;see docstring for "xy"
|
||||
(tramp-default-port 22)))
|
||||
;;;###tramp-autoload
|
||||
(add-to-list 'tramp-methods
|
||||
|
@ -397,8 +395,7 @@ detected as prompt when being sent on echoing hosts, therefore.")
|
|||
(tramp-copy-args (("-l" "%u") ("-P" "%p") ("-sftp") ("-p" "%k")
|
||||
("-q") ("-r")))
|
||||
(tramp-copy-keep-date t)
|
||||
(tramp-copy-recursive t)
|
||||
(tramp-password-end-of-line "xy"))) ;see docstring for "xy"
|
||||
(tramp-copy-recursive t)))
|
||||
;;;###tramp-autoload
|
||||
(add-to-list 'tramp-methods
|
||||
'("fcp"
|
||||
|
@ -462,9 +459,11 @@ detected as prompt when being sent on echoing hosts, therefore.")
|
|||
|
||||
;;;###tramp-autoload
|
||||
(defconst tramp-completion-function-alist-putty
|
||||
'((tramp-parse-putty
|
||||
"HKEY_CURRENT_USER\\Software\\SimonTatham\\PuTTY\\Sessions"))
|
||||
"Default list of (FUNCTION REGISTRY) pairs to be examined for putty methods.")
|
||||
`((tramp-parse-putty
|
||||
,(if (memq system-type '(windows-nt))
|
||||
"HKEY_CURRENT_USER\\Software\\SimonTatham\\PuTTY\\Sessions"
|
||||
"~/.putty/sessions")))
|
||||
"Default list of (FUNCTION REGISTRY) pairs to be examined for putty sessions.")
|
||||
|
||||
;;;###tramp-autoload
|
||||
(eval-after-load 'tramp
|
||||
|
@ -513,9 +512,10 @@ detected as prompt when being sent on echoing hosts, therefore.")
|
|||
;; IRIX64: /usr/bin
|
||||
;;;###tramp-autoload
|
||||
(defcustom tramp-remote-path
|
||||
'(tramp-default-remote-path "/bin" "/usr/bin" "/usr/sbin" "/usr/local/bin"
|
||||
"/local/bin" "/local/freeware/bin" "/local/gnu/bin"
|
||||
"/usr/freeware/bin" "/usr/pkg/bin" "/usr/contrib/bin")
|
||||
'(tramp-default-remote-path "/bin" "/usr/bin" "/usr/sbin"
|
||||
"/usr/local/bin" "/local/bin" "/local/freeware/bin" "/local/gnu/bin"
|
||||
"/usr/freeware/bin" "/usr/pkg/bin" "/usr/contrib/bin"
|
||||
"/opt/bin" "/opt/sbin" "/opt/local/bin")
|
||||
"List of directories to search for executables on remote host.
|
||||
For every remote host, this variable will be set buffer local,
|
||||
keeping the list of existing directories on that host.
|
||||
|
@ -545,7 +545,6 @@ as given in your `~/.profile'."
|
|||
,(format "INSIDE_EMACS='%s,tramp:%s'" emacs-version tramp-version)
|
||||
"CDPATH=" "HISTORY=" "MAIL=" "MAILCHECK=" "MAILPATH=" "PAGER=\"\""
|
||||
"autocorrect=" "correct=")
|
||||
|
||||
"List of environment variables to be set on the remote host.
|
||||
|
||||
Each element should be a string of the form ENVVARNAME=VALUE. An
|
||||
|
@ -1180,9 +1179,6 @@ target of the symlink differ."
|
|||
(tramp-get-file-exists-command v)
|
||||
(tramp-shell-quote-argument localname)))))))
|
||||
|
||||
;; CCC: This should check for an error condition and signal failure
|
||||
;; when something goes wrong.
|
||||
;; Daniel Pittman <daniel@danann.net>
|
||||
(defun tramp-sh-handle-file-attributes (filename &optional id-format)
|
||||
"Like `file-attributes' for Tramp files."
|
||||
(unless id-format (setq id-format 'integer))
|
||||
|
@ -1318,8 +1314,8 @@ target of the symlink differ."
|
|||
(tramp-get-test-command vec)
|
||||
(tramp-shell-quote-argument localname)
|
||||
(tramp-get-remote-stat vec)
|
||||
(if (eq id-format 'integer) "%u" "\"%U\"")
|
||||
(if (eq id-format 'integer) "%g" "\"%G\"")
|
||||
(if (eq id-format 'integer) "%ue0" "\"%U\"")
|
||||
(if (eq id-format 'integer) "%ge0" "\"%G\"")
|
||||
(tramp-shell-quote-argument localname))))
|
||||
|
||||
(defun tramp-sh-handle-set-visited-file-modtime (&optional time-list)
|
||||
|
@ -1702,8 +1698,8 @@ and gid of the corresponding user is taken. Both parameters must be integers."
|
|||
(tramp-shell-quote-argument localname)
|
||||
(tramp-get-ls-command vec)
|
||||
(tramp-get-remote-stat vec)
|
||||
(if (eq id-format 'integer) "%u" "\"%U\"")
|
||||
(if (eq id-format 'integer) "%g" "\"%G\""))))
|
||||
(if (eq id-format 'integer) "%ue0" "\"%U\"")
|
||||
(if (eq id-format 'integer) "%ge0" "\"%G\""))))
|
||||
|
||||
;; This function should return "foo/" for directories and "bar" for
|
||||
;; files.
|
||||
|
@ -2394,7 +2390,7 @@ The method used must be an out-of-band method."
|
|||
p v nil tramp-actions-copy-out-of-band)))
|
||||
|
||||
;; Reset the transfer process properties.
|
||||
(tramp-message orig-vec 6 "%s" (buffer-string))
|
||||
(tramp-message orig-vec 6 "\n%s" (buffer-string))
|
||||
(tramp-set-connection-property v "process-name" nil)
|
||||
(tramp-set-connection-property v "process-buffer" nil)))
|
||||
|
||||
|
@ -2457,11 +2453,11 @@ The method used must be an out-of-band method."
|
|||
"Recursively delete the directory given.
|
||||
This is like `dired-recursive-delete-directory' for Tramp files."
|
||||
(with-parsed-tramp-file-name filename nil
|
||||
;; Run a shell command 'rm -r <localname>'
|
||||
;; Run a shell command 'rm -r <localname>'.
|
||||
;; Code shamelessly stolen from the dired implementation and, um, hacked :)
|
||||
(unless (file-exists-p filename)
|
||||
(tramp-error v 'file-error "No such directory: %s" filename))
|
||||
;; Which is better, -r or -R? (-r works for me <daniel@danann.net>)
|
||||
;; Which is better, -r or -R? (-r works for me <daniel@danann.net>).
|
||||
(tramp-send-command
|
||||
v
|
||||
(format "rm -rf %s" (tramp-shell-quote-argument localname))
|
||||
|
@ -2699,7 +2695,8 @@ the result will be a local, non-Tramp, filename."
|
|||
method user host
|
||||
(tramp-drop-volume-letter
|
||||
(tramp-run-real-handler
|
||||
'expand-file-name (list localname))))))))
|
||||
'expand-file-name (list localname)))
|
||||
hop)))))
|
||||
|
||||
;;; Remote commands:
|
||||
|
||||
|
@ -3609,37 +3606,48 @@ file exists and nonzero exit status otherwise."
|
|||
|
||||
(defun tramp-find-shell (vec)
|
||||
"Opens a shell on the remote host which groks tilde expansion."
|
||||
(unless (tramp-get-connection-property vec "remote-shell" nil)
|
||||
(let (shell)
|
||||
(with-connection-property vec "remote-shell"
|
||||
(let ((shell (tramp-get-method-parameter
|
||||
(tramp-file-name-method vec) 'tramp-remote-shell)))
|
||||
(with-current-buffer (tramp-get-buffer vec)
|
||||
;; CCC: "root" does not exist always, see QNAP 459. Which
|
||||
;; check could we apply instead?
|
||||
(tramp-send-command vec "echo ~root" t)
|
||||
(cond
|
||||
((or (string-match "^~root$" (buffer-string))
|
||||
;; The default shell (ksh93) of OpenSolaris and Solaris
|
||||
;; is buggy. We've got reports for "SunOS 5.10" and
|
||||
;; "SunOS 5.11" so far.
|
||||
(string-match (regexp-opt '("SunOS 5.10" "SunOS 5.11"))
|
||||
(tramp-get-connection-property vec "uname" "")))
|
||||
(setq shell
|
||||
(or (tramp-find-executable
|
||||
vec "bash" (tramp-get-remote-path vec) t t)
|
||||
(tramp-find-executable
|
||||
vec "ksh" (tramp-get-remote-path vec) t t)))
|
||||
(unless shell
|
||||
(tramp-error
|
||||
vec 'file-error
|
||||
"Couldn't find a shell which groks tilde expansion"))
|
||||
(tramp-message
|
||||
vec 5 "Starting remote shell `%s' for tilde expansion"
|
||||
(tramp-set-connection-property vec "remote-shell" shell))
|
||||
(tramp-open-shell vec shell))
|
||||
(when (or (string-match "^~root$" (buffer-string))
|
||||
;; The default shell (ksh93) of OpenSolaris and
|
||||
;; Solaris is buggy. We've got reports for "SunOS
|
||||
;; 5.10" and "SunOS 5.11" so far.
|
||||
(string-match (regexp-opt '("SunOS 5.10" "SunOS 5.11"))
|
||||
(tramp-get-connection-property vec "uname" "")))
|
||||
(if (setq shell
|
||||
(or (tramp-find-executable
|
||||
vec "bash" (tramp-get-remote-path vec) t t)
|
||||
(tramp-find-executable
|
||||
vec "ksh" (tramp-get-remote-path vec) t t)))
|
||||
(progn
|
||||
(tramp-message
|
||||
vec 5 "Starting remote shell `%s' for tilde expansion" shell)
|
||||
(tramp-open-shell vec shell))
|
||||
|
||||
(t (tramp-message
|
||||
vec 5 "Remote `%s' groks tilde expansion, good"
|
||||
(tramp-set-connection-property
|
||||
vec "remote-shell"
|
||||
(tramp-get-method-parameter
|
||||
(tramp-file-name-method vec) 'tramp-remote-shell)))))))))
|
||||
;; Maybe it works at least for some other commands.
|
||||
(setq shell
|
||||
(tramp-get-method-parameter
|
||||
(tramp-file-name-method vec) 'tramp-remote-shell))
|
||||
(tramp-message
|
||||
vec 2
|
||||
(concat
|
||||
"Couldn't find a remote shell which groks tilde expansion, "
|
||||
"using `%s'")
|
||||
shell)))
|
||||
|
||||
;; Busyboxes tend to behave strange. We check for the existence.
|
||||
(with-connection-property vec "busybox"
|
||||
(tramp-send-command vec (format "%s --version" shell) t)
|
||||
(let ((case-fold-search t))
|
||||
(and (string-match "busybox" (buffer-string)) t)))
|
||||
|
||||
;; Return the shell.
|
||||
shell))))
|
||||
|
||||
;; Utility functions.
|
||||
|
||||
|
@ -3747,21 +3755,12 @@ process to set up. VEC specifies the connection."
|
|||
vec "uname"
|
||||
(tramp-send-command-and-read vec "echo \\\"`uname -sr`\\\""))))
|
||||
(when (and (stringp old-uname) (not (string-equal old-uname new-uname)))
|
||||
(with-current-buffer (tramp-get-debug-buffer vec)
|
||||
;; Keep the debug buffer.
|
||||
(rename-buffer
|
||||
(generate-new-buffer-name tramp-temp-buffer-name) 'unique)
|
||||
(tramp-cleanup-connection vec)
|
||||
(if (= (point-min) (point-max))
|
||||
(kill-buffer nil)
|
||||
(rename-buffer (tramp-debug-buffer-name vec) 'unique))
|
||||
;; We call `tramp-get-buffer' in order to keep the debug buffer.
|
||||
(tramp-get-buffer vec)
|
||||
(tramp-message
|
||||
vec 3
|
||||
"Connection reset, because remote host changed from `%s' to `%s'"
|
||||
old-uname new-uname)
|
||||
(throw 'uname-changed (tramp-maybe-open-connection vec)))))
|
||||
(tramp-cleanup vec)
|
||||
(tramp-message
|
||||
vec 3
|
||||
"Connection reset, because remote host changed from `%s' to `%s'"
|
||||
old-uname new-uname)
|
||||
(throw 'uname-changed (tramp-maybe-open-connection vec))))
|
||||
|
||||
;; Check whether the remote host suffers from buggy
|
||||
;; `send-process-string'. This is known for FreeBSD (see comment in
|
||||
|
@ -3798,17 +3797,6 @@ process to set up. VEC specifies the connection."
|
|||
;; Disable unexpected output.
|
||||
(tramp-send-command vec "mesg n; biff n" t)
|
||||
|
||||
;; Busyboxes tend to behave strange. We check for the existence.
|
||||
(with-connection-property vec "busybox"
|
||||
(tramp-send-command
|
||||
vec
|
||||
(format
|
||||
"%s --version" (tramp-get-connection-property vec "remote-shell" "echo"))
|
||||
t)
|
||||
(with-current-buffer (process-buffer proc)
|
||||
(let ((case-fold-search t))
|
||||
(and (string-match "busybox" (buffer-string)) t))))
|
||||
|
||||
;; IRIX64 bash expands "!" even when in single quotes. This
|
||||
;; destroys our shell functions, we must disable it. See
|
||||
;; <http://stackoverflow.com/questions/3291692/irix-bash-shell-expands-expression-in-single-quotes-yet-shouldnt>.
|
||||
|
@ -3902,7 +3890,7 @@ with the encoded or decoded results, respectively.")
|
|||
(b64 "recode data..base64" "recode base64..data")
|
||||
(b64 tramp-perl-encode-with-module tramp-perl-decode-with-module)
|
||||
(b64 tramp-perl-encode tramp-perl-decode)
|
||||
(uu "uuencode xxx" "uudecode -o /dev/stdout")
|
||||
(uu "uuencode xxx" "uudecode -o /dev/stdout" "test -c /dev/stdout")
|
||||
(uu "uuencode xxx" "uudecode -o -")
|
||||
(uu "uuencode xxx" "uudecode -p")
|
||||
(uu "uuencode xxx" tramp-uudecode)
|
||||
|
@ -3912,7 +3900,7 @@ with the encoded or decoded results, respectively.")
|
|||
"List of remote coding commands for inline transfer.
|
||||
Each item is a list that looks like this:
|
||||
|
||||
\(FORMAT ENCODING DECODING\)
|
||||
\(FORMAT ENCODING DECODING [TEST]\)
|
||||
|
||||
FORMAT is symbol describing the encoding/decoding format. It can be
|
||||
`b64' for base64 encoding, `uu' for uu encoding, or `pack' for simple packing.
|
||||
|
@ -3926,7 +3914,10 @@ input.
|
|||
|
||||
If they are variables, this variable is a string containing a Perl
|
||||
implementation for this functionality. This Perl program will be transferred
|
||||
to the remote host, and it is available as shell function with the same name.")
|
||||
to the remote host, and it is available as shell function with the same name.
|
||||
|
||||
The optional TEST command can be used for further tests, whether
|
||||
ENCODING and DECODING are applicable.")
|
||||
|
||||
(defun tramp-find-inline-encoding (vec)
|
||||
"Find an inline transfer encoding that works.
|
||||
|
@ -3935,7 +3926,8 @@ Goes through the list `tramp-local-coding-commands' and
|
|||
(save-excursion
|
||||
(let ((local-commands tramp-local-coding-commands)
|
||||
(magic "xyzzy")
|
||||
loc-enc loc-dec rem-enc rem-dec litem ritem found)
|
||||
(p (tramp-get-connection-process vec))
|
||||
loc-enc loc-dec rem-enc rem-dec rem-test litem ritem found)
|
||||
(while (and local-commands (not found))
|
||||
(setq litem (pop local-commands))
|
||||
(catch 'wont-work-local
|
||||
|
@ -3968,6 +3960,13 @@ Goes through the list `tramp-local-coding-commands' and
|
|||
(when (equal format (nth 0 ritem))
|
||||
(setq rem-enc (nth 1 ritem))
|
||||
(setq rem-dec (nth 2 ritem))
|
||||
(setq rem-test (nth 3 ritem))
|
||||
;; Check the remote test command if exists.
|
||||
(when (stringp rem-test)
|
||||
(tramp-message
|
||||
vec 5 "Checking remote test command `%s'" rem-test)
|
||||
(unless (tramp-send-command-and-check vec rem-test t)
|
||||
(throw 'wont-work-remote nil)))
|
||||
;; Check if remote encoding and decoding commands can be
|
||||
;; called remotely with null input and output. This makes
|
||||
;; sure there are no syntax errors and the command is really
|
||||
|
@ -4019,15 +4018,16 @@ Goes through the list `tramp-local-coding-commands' and
|
|||
(tramp-error
|
||||
vec 'file-error "Couldn't find an inline transfer encoding"))
|
||||
|
||||
;; Set connection properties.
|
||||
;; Set connection properties. Since the commands are risky (due
|
||||
;; to output direction), we cache them in the process cache.
|
||||
(tramp-message vec 5 "Using local encoding `%s'" loc-enc)
|
||||
(tramp-set-connection-property vec "local-encoding" loc-enc)
|
||||
(tramp-set-connection-property p "local-encoding" loc-enc)
|
||||
(tramp-message vec 5 "Using local decoding `%s'" loc-dec)
|
||||
(tramp-set-connection-property vec "local-decoding" loc-dec)
|
||||
(tramp-set-connection-property p "local-decoding" loc-dec)
|
||||
(tramp-message vec 5 "Using remote encoding `%s'" rem-enc)
|
||||
(tramp-set-connection-property vec "remote-encoding" rem-enc)
|
||||
(tramp-set-connection-property p "remote-encoding" rem-enc)
|
||||
(tramp-message vec 5 "Using remote decoding `%s'" rem-dec)
|
||||
(tramp-set-connection-property vec "remote-decoding" rem-dec))))
|
||||
(tramp-set-connection-property p "remote-decoding" rem-dec))))
|
||||
|
||||
(defun tramp-call-local-coding-command (cmd input output)
|
||||
"Call the local encoding or decoding command.
|
||||
|
@ -4065,8 +4065,8 @@ Goes through the list `tramp-inline-compress-commands'."
|
|||
(save-excursion
|
||||
(let ((commands tramp-inline-compress-commands)
|
||||
(magic "xyzzy")
|
||||
item compress decompress
|
||||
found)
|
||||
(p (tramp-get-connection-process vec))
|
||||
item compress decompress found)
|
||||
(while (and commands (not found))
|
||||
(catch 'next
|
||||
(setq item (pop commands)
|
||||
|
@ -4100,16 +4100,18 @@ Goes through the list `tramp-inline-compress-commands'."
|
|||
;; Did we find something?
|
||||
(if found
|
||||
(progn
|
||||
;; Set connection properties.
|
||||
;; Set connection properties. Since the commands are
|
||||
;; risky (due to output direction), we cache them in the
|
||||
;; process cache.
|
||||
(tramp-message
|
||||
vec 5 "Using inline transfer compress command `%s'" compress)
|
||||
(tramp-set-connection-property vec "inline-compress" compress)
|
||||
(tramp-set-connection-property p "inline-compress" compress)
|
||||
(tramp-message
|
||||
vec 5 "Using inline transfer decompress command `%s'" decompress)
|
||||
(tramp-set-connection-property vec "inline-decompress" decompress))
|
||||
(tramp-set-connection-property p "inline-decompress" decompress))
|
||||
|
||||
(tramp-set-connection-property vec "inline-compress" nil)
|
||||
(tramp-set-connection-property vec "inline-decompress" nil)
|
||||
(tramp-set-connection-property p "inline-compress" nil)
|
||||
(tramp-set-connection-property p "inline-decompress" nil)
|
||||
(tramp-message
|
||||
vec 2 "Couldn't find an inline transfer compress command")))))
|
||||
|
||||
|
@ -4117,18 +4119,43 @@ Goes through the list `tramp-inline-compress-commands'."
|
|||
"Expands VEC according to `tramp-default-proxies-alist'.
|
||||
Gateway hops are already opened."
|
||||
(let ((target-alist `(,vec))
|
||||
(choices tramp-default-proxies-alist)
|
||||
item proxy)
|
||||
(hops (or (tramp-file-name-hop vec) ""))
|
||||
(item vec)
|
||||
choices proxy)
|
||||
|
||||
;; Ad-hoc proxy definitions.
|
||||
(dolist (proxy (reverse (split-string hops tramp-postfix-hop-regexp 'omit)))
|
||||
(let ((user (tramp-file-name-user item))
|
||||
(host (tramp-file-name-host item))
|
||||
(proxy (concat
|
||||
tramp-prefix-format proxy tramp-postfix-host-format)))
|
||||
(tramp-message
|
||||
vec 5 "Add proxy (\"%s\" \"%s\" \"%s\")"
|
||||
(and (stringp host) (regexp-quote host))
|
||||
(and (stringp user) (regexp-quote user))
|
||||
proxy)
|
||||
;; Add the hop.
|
||||
(add-to-list
|
||||
'tramp-default-proxies-alist
|
||||
(list (and (stringp host) (regexp-quote host))
|
||||
(and (stringp user) (regexp-quote user))
|
||||
proxy))
|
||||
(setq item (tramp-dissect-file-name proxy))))
|
||||
;; Save the new value.
|
||||
(when (and hops tramp-save-ad-hoc-proxies)
|
||||
(customize-save-variable
|
||||
'tramp-default-proxies-alist tramp-default-proxies-alist))
|
||||
|
||||
;; Look for proxy hosts to be passed.
|
||||
(setq choices tramp-default-proxies-alist)
|
||||
(while choices
|
||||
(setq item (pop choices)
|
||||
proxy (eval (nth 2 item)))
|
||||
(when (and
|
||||
;; host
|
||||
;; Host.
|
||||
(string-match (or (eval (nth 0 item)) "")
|
||||
(or (tramp-file-name-host (car target-alist)) ""))
|
||||
;; user
|
||||
;; User.
|
||||
(string-match (or (eval (nth 1 item)) "")
|
||||
(or (tramp-file-name-user (car target-alist)) "")))
|
||||
(if (null proxy)
|
||||
|
@ -4164,7 +4191,7 @@ Gateway hops are already opened."
|
|||
'target-alist
|
||||
(vector
|
||||
(tramp-file-name-method hop) (tramp-file-name-user hop)
|
||||
(tramp-compat-funcall 'tramp-gw-open-connection vec gw hop) nil))
|
||||
(tramp-compat-funcall 'tramp-gw-open-connection vec gw hop) nil nil))
|
||||
;; For the password prompt, we need the correct values.
|
||||
;; Therefore, we must remember the gateway vector. But we
|
||||
;; cannot do it as connection property, because it shouldn't
|
||||
|
@ -4212,6 +4239,9 @@ Gateway hops are already opened."
|
|||
;; Result.
|
||||
target-alist))
|
||||
|
||||
(defvar tramp-current-connection nil
|
||||
"Last connection timestamp.")
|
||||
|
||||
(defun tramp-maybe-open-connection (vec)
|
||||
"Maybe open a connection VEC.
|
||||
Does not do anything if a connection is already open, but re-opens the
|
||||
|
@ -4222,6 +4252,16 @@ connection if a previous connection has died for some reason."
|
|||
(process-environment (copy-sequence process-environment))
|
||||
(pos (with-current-buffer (tramp-get-connection-buffer vec) (point))))
|
||||
|
||||
;; If Tramp opens the same connection within a short time frame,
|
||||
;; there is a problem. We shall signal this.
|
||||
(unless (or (and p (processp p) (memq (process-status p) '(run open)))
|
||||
(not (equal (butlast (append vec nil))
|
||||
(car tramp-current-connection)))
|
||||
(> (tramp-time-diff
|
||||
(current-time) (cdr tramp-current-connection))
|
||||
5))
|
||||
(throw 'suppress 'suppress))
|
||||
|
||||
;; If too much time has passed since last command was sent, look
|
||||
;; whether process is still alive. If it isn't, kill it. When
|
||||
;; using ssh, it can sometimes happen that the remote end has
|
||||
|
@ -4242,9 +4282,7 @@ connection if a previous connection has died for some reason."
|
|||
;; The error will be caught locally.
|
||||
(tramp-error vec 'file-error "Awake did fail")))
|
||||
(file-error
|
||||
(tramp-flush-connection-property vec)
|
||||
(tramp-flush-connection-property p)
|
||||
(delete-process p)
|
||||
(tramp-cleanup vec)
|
||||
(setq p nil)))
|
||||
|
||||
;; New connection must be opened.
|
||||
|
@ -4293,6 +4331,8 @@ connection if a previous connection has died for some reason."
|
|||
(tramp-set-connection-property p "vector" vec)
|
||||
(set-process-sentinel p 'tramp-process-sentinel)
|
||||
(tramp-compat-set-process-query-on-exit-flag p nil)
|
||||
(setq tramp-current-connection
|
||||
(cons (butlast (append vec nil)) (current-time)))
|
||||
|
||||
(tramp-message
|
||||
vec 6 "%s" (mapconcat 'identity (process-command p) " "))
|
||||
|
@ -4401,11 +4441,7 @@ connection if a previous connection has died for some reason."
|
|||
|
||||
;; When the user did interrupt, we must cleanup.
|
||||
(quit
|
||||
(let ((p (tramp-get-connection-process vec)))
|
||||
(when (and p (processp p))
|
||||
(tramp-flush-connection-property vec)
|
||||
(tramp-flush-connection-property p)
|
||||
(delete-process p)))
|
||||
(tramp-cleanup vec)
|
||||
;; Propagate the quit signal.
|
||||
(signal (car err) (cdr err)))))))
|
||||
|
||||
|
@ -4942,9 +4978,10 @@ the length of the file to be compressed.
|
|||
If no corresponding command is found, nil is returned."
|
||||
(when (and (integerp tramp-inline-compress-start-size)
|
||||
(> size tramp-inline-compress-start-size))
|
||||
(with-connection-property vec prop
|
||||
(with-connection-property (tramp-get-connection-process vec) prop
|
||||
(tramp-find-inline-compress vec)
|
||||
(tramp-get-connection-property vec prop nil))))
|
||||
(tramp-get-connection-property
|
||||
(tramp-get-connection-process vec) prop nil))))
|
||||
|
||||
(defun tramp-get-inline-coding (vec prop size)
|
||||
"Return the coding command related to PROP.
|
||||
|
@ -4962,9 +4999,10 @@ function cell is returned to be applied on a buffer."
|
|||
;; no inline coding is found.
|
||||
(ignore-errors
|
||||
(let ((coding
|
||||
(with-connection-property vec prop
|
||||
(with-connection-property (tramp-get-connection-process vec) prop
|
||||
(tramp-find-inline-encoding vec)
|
||||
(tramp-get-connection-property vec prop nil)))
|
||||
(tramp-get-connection-property
|
||||
(tramp-get-connection-process vec) prop nil)))
|
||||
(prop1 (if (string-match "encoding" prop)
|
||||
"inline-compress" "inline-decompress"))
|
||||
compress)
|
||||
|
|
|
@ -43,7 +43,7 @@
|
|||
;; We define an empty command, because `tramp-smb-call-winexe'
|
||||
;; opens already the powershell. Used in `tramp-handle-shell-command'.
|
||||
(tramp-remote-shell "")
|
||||
;; This is just a guess. We don't know whether the share "$C"
|
||||
;; This is just a guess. We don't know whether the share "C$"
|
||||
;; is available for public use, and whether the user has write
|
||||
;; access.
|
||||
(tramp-tmpdir "/C$/Temp"))))
|
||||
|
@ -82,8 +82,18 @@ call, letting the SMB client use the default one."
|
|||
(defvar tramp-smb-version nil
|
||||
"Version string of the SMB client.")
|
||||
|
||||
(defconst tramp-smb-prompt "^smb: .+> \\|^\\s-+Server\\s-+Comment$"
|
||||
"Regexp used as prompt in smbclient.")
|
||||
(defconst tramp-smb-server-version
|
||||
"Domain=\\[[^]]*\\] OS=\\[[^]]*\\] Server=\\[[^]]*\\]"
|
||||
"Regexp of SMB server identification.")
|
||||
|
||||
(defconst tramp-smb-prompt "^\\(smb:\\|PS\\) .+> \\|^\\s-+Server\\s-+Comment$"
|
||||
"Regexp used as prompt in smbclient or powershell.")
|
||||
|
||||
(defconst tramp-smb-wrong-passwd-regexp
|
||||
(regexp-opt
|
||||
'("NT_STATUS_LOGON_FAILURE"
|
||||
"NT_STATUS_WRONG_PASSWORD"))
|
||||
"Regexp for login error strings of SMB servers.")
|
||||
|
||||
(defconst tramp-smb-errors
|
||||
(mapconcat
|
||||
|
@ -155,6 +165,16 @@ This list is used for login to SMB servers.
|
|||
|
||||
See `tramp-actions-before-shell' for more info.")
|
||||
|
||||
(defconst tramp-smb-actions-with-tar
|
||||
'((tramp-password-prompt-regexp tramp-action-password)
|
||||
(tramp-wrong-passwd-regexp tramp-action-permission-denied)
|
||||
(tramp-smb-errors tramp-action-permission-denied)
|
||||
(tramp-process-alive-regexp tramp-smb-action-with-tar))
|
||||
"List of pattern/action pairs.
|
||||
This list is used for tar-like copy of directories.
|
||||
|
||||
See `tramp-actions-before-shell' for more info.")
|
||||
|
||||
;; New handlers should be added here.
|
||||
(defconst tramp-smb-file-name-handler-alist
|
||||
'(
|
||||
|
@ -205,12 +225,14 @@ See `tramp-actions-before-shell' for more info.")
|
|||
(make-directory . tramp-smb-handle-make-directory)
|
||||
(make-directory-internal . tramp-smb-handle-make-directory-internal)
|
||||
(make-symbolic-link . tramp-smb-handle-make-symbolic-link)
|
||||
(process-file . tramp-smb-handle-process-file)
|
||||
(rename-file . tramp-smb-handle-rename-file)
|
||||
(set-file-modes . tramp-smb-handle-set-file-modes)
|
||||
;; `set-file-selinux-context' performed by default handler.
|
||||
(set-file-times . ignore)
|
||||
(set-visited-file-modtime . ignore)
|
||||
(shell-command . ignore)
|
||||
(shell-command . tramp-handle-shell-command)
|
||||
(start-file-process . tramp-smb-handle-start-file-process)
|
||||
(substitute-in-file-name . tramp-smb-handle-substitute-in-file-name)
|
||||
(unhandled-file-name-directory . tramp-handle-unhandled-file-name-directory)
|
||||
(vc-registered . ignore)
|
||||
|
@ -220,11 +242,34 @@ See `tramp-actions-before-shell' for more info.")
|
|||
"Alist of handler functions for Tramp SMB method.
|
||||
Operations not mentioned here will be handled by the default Emacs primitives.")
|
||||
|
||||
;; Options for remote processes via winexe.
|
||||
(defcustom tramp-smb-winexe-program "winexe"
|
||||
"Name of winexe client to run.
|
||||
If it isn't found in the local $PATH, the absolute path of winexe
|
||||
shall be given. This is needed for remote processes."
|
||||
:group 'tramp
|
||||
:type 'string
|
||||
:version "24.2")
|
||||
|
||||
(defcustom tramp-smb-winexe-shell-command "powershell.exe"
|
||||
"Shell to be used for processes on remote machines.
|
||||
This must be Powershell V2 compatible."
|
||||
:group 'tramp
|
||||
:type 'string
|
||||
:version "24.2")
|
||||
|
||||
(defcustom tramp-smb-winexe-shell-command-switch "-file -"
|
||||
"Command switch used together with `tramp-smb-winexe-shell-command'.
|
||||
This can be used to disable echo etc."
|
||||
:group 'tramp
|
||||
:type 'string
|
||||
:version "24.2")
|
||||
|
||||
;;;###tramp-autoload
|
||||
(defsubst tramp-smb-file-name-p (filename)
|
||||
"Check if it's a filename for SMB servers."
|
||||
(let ((v (tramp-dissect-file-name filename)))
|
||||
(string= (tramp-file-name-method v) tramp-smb-method)))
|
||||
(string= (tramp-file-name-method (tramp-dissect-file-name filename))
|
||||
tramp-smb-method))
|
||||
|
||||
;;;###tramp-autoload
|
||||
(defun tramp-smb-file-name-handler (operation &rest args)
|
||||
|
@ -287,14 +332,31 @@ pass to the OPERATION."
|
|||
"error with add-name-to-file, see buffer `%s' for details"
|
||||
(buffer-name))))))
|
||||
|
||||
(defun tramp-smb-action-with-tar (proc vec)
|
||||
"Untar from connection buffer."
|
||||
(if (not (memq (process-status proc) '(run open)))
|
||||
(throw 'tramp-action 'process-died)
|
||||
|
||||
(with-current-buffer (tramp-get-connection-buffer vec)
|
||||
(goto-char (point-min))
|
||||
(when (search-forward-regexp tramp-smb-server-version nil t)
|
||||
;; There might be a hidden password prompt.
|
||||
(widen)
|
||||
(forward-line)
|
||||
(tramp-message vec 6 (buffer-substring (point-min) (point)))
|
||||
(delete-region (point-min) (point))
|
||||
(throw 'tramp-action 'ok)))))
|
||||
|
||||
(defun tramp-smb-handle-copy-directory
|
||||
(dirname newname &optional keep-date parents copy-contents)
|
||||
"Like `copy-directory' for Tramp files. KEEP-DATE is not handled."
|
||||
"Like `copy-directory' for Tramp files."
|
||||
(setq dirname (expand-file-name dirname)
|
||||
newname (expand-file-name newname))
|
||||
(let ((t1 (tramp-tramp-file-p dirname))
|
||||
(t2 (tramp-tramp-file-p newname)))
|
||||
(with-parsed-tramp-file-name (if t1 dirname newname) nil
|
||||
(tramp-with-progress-reporter
|
||||
v 0 (format "Copying %s to %s" dirname newname)
|
||||
(cond
|
||||
;; We must use a local temporary directory.
|
||||
((and t1 t2)
|
||||
|
@ -311,46 +373,121 @@ pass to the OPERATION."
|
|||
|
||||
;; We can copy recursively.
|
||||
((or t1 t2)
|
||||
(let ((prompt (tramp-smb-send-command v "prompt"))
|
||||
(recurse (tramp-smb-send-command v "recurse")))
|
||||
(unless (file-directory-p newname)
|
||||
(when (and (file-directory-p newname)
|
||||
(not (string-equal (file-name-nondirectory dirname)
|
||||
(file-name-nondirectory newname))))
|
||||
(setq newname
|
||||
(expand-file-name
|
||||
(file-name-nondirectory dirname) newname))
|
||||
(if t2 (setq v (tramp-dissect-file-name newname))))
|
||||
(if (not (file-directory-p newname))
|
||||
(make-directory newname parents))
|
||||
|
||||
(setq tramp-current-method (tramp-file-name-method v)
|
||||
tramp-current-user (tramp-file-name-user v)
|
||||
tramp-current-host (tramp-file-name-real-host v))
|
||||
|
||||
(let* ((real-user (tramp-file-name-real-user v))
|
||||
(real-host (tramp-file-name-real-host v))
|
||||
(domain (tramp-file-name-domain v))
|
||||
(port (tramp-file-name-port v))
|
||||
(share (tramp-smb-get-share v))
|
||||
(localname (file-name-as-directory
|
||||
(replace-regexp-in-string
|
||||
"\\\\" "/" (tramp-smb-get-localname v))))
|
||||
(tmpdir (make-temp-name
|
||||
(expand-file-name
|
||||
tramp-temp-name-prefix
|
||||
(tramp-compat-temporary-file-directory))))
|
||||
(args (list tramp-smb-program
|
||||
(concat "//" real-host "/" share) "-E")))
|
||||
|
||||
(if (not (zerop (length real-user)))
|
||||
(setq args (append args (list "-U" real-user)))
|
||||
(setq args (append args (list "-N"))))
|
||||
|
||||
(when domain (setq args (append args (list "-W" domain))))
|
||||
(when port (setq args (append args (list "-p" port))))
|
||||
(when tramp-smb-conf
|
||||
(setq args (append args (list "-s" tramp-smb-conf))))
|
||||
(setq args
|
||||
(if t1
|
||||
;; Source is remote.
|
||||
(append args
|
||||
(list "-D" (shell-quote-argument localname)
|
||||
"-c" (shell-quote-argument "tar qc - *")
|
||||
"|" "tar" "xfC" "-"
|
||||
(shell-quote-argument tmpdir)))
|
||||
;; Target is remote.
|
||||
(append (list "tar" "cfC" "-" (shell-quote-argument dirname)
|
||||
"." "|")
|
||||
args
|
||||
(list "-D" (shell-quote-argument localname)
|
||||
"-c" (shell-quote-argument "tar qx -")))))
|
||||
|
||||
(unwind-protect
|
||||
(unless
|
||||
(and
|
||||
prompt recurse
|
||||
(tramp-smb-send-command
|
||||
v (format "cd \"%s\"" (tramp-smb-get-localname v)))
|
||||
(tramp-smb-send-command
|
||||
v (format "lcd \"%s\"" (if t1 newname dirname)))
|
||||
(if t1
|
||||
(tramp-smb-send-command v "mget *")
|
||||
(tramp-smb-send-command v "mput *")))
|
||||
;; Error.
|
||||
(with-current-buffer (tramp-get-connection-buffer v)
|
||||
(goto-char (point-min))
|
||||
(search-forward-regexp tramp-smb-errors nil t)
|
||||
(tramp-error
|
||||
v 'file-error
|
||||
"%s `%s'" (match-string 0) (if t1 dirname newname))))
|
||||
;; Go home.
|
||||
(tramp-smb-send-command
|
||||
v (format
|
||||
"cd %s" (if (tramp-smb-get-cifs-capabilities v) "/" "\\")))
|
||||
;; Toggle prompt and recurse OFF.
|
||||
(if prompt (tramp-smb-send-command v "prompt"))
|
||||
(if recurse (tramp-smb-send-command v "recurse")))))
|
||||
(with-temp-buffer
|
||||
;; Set the transfer process properties.
|
||||
(tramp-set-connection-property
|
||||
v "process-name" (buffer-name (current-buffer)))
|
||||
(tramp-set-connection-property
|
||||
v "process-buffer" (current-buffer))
|
||||
|
||||
(when t1
|
||||
;; The smbclient tar command creates always complete
|
||||
;; paths. We must emulate the directory structure,
|
||||
;; and symlink to the real target.
|
||||
(make-directory
|
||||
(expand-file-name ".." (concat tmpdir localname)) 'parents)
|
||||
(make-symbolic-link
|
||||
newname (directory-file-name (concat tmpdir localname))))
|
||||
|
||||
;; Use an asynchronous processes. By this, password
|
||||
;; can be handled.
|
||||
(let* ((default-directory tmpdir)
|
||||
(p (start-process-shell-command
|
||||
(tramp-get-connection-name v)
|
||||
(tramp-get-connection-buffer v)
|
||||
(mapconcat 'identity args " "))))
|
||||
|
||||
(tramp-message
|
||||
v 6 "%s" (mapconcat 'identity (process-command p) " "))
|
||||
(tramp-compat-set-process-query-on-exit-flag p nil)
|
||||
(tramp-process-actions p v nil tramp-smb-actions-with-tar)
|
||||
|
||||
(while (memq (process-status p) '(run open))
|
||||
(sit-for 0.1))
|
||||
(tramp-message v 6 "\n%s" (buffer-string))))
|
||||
|
||||
;; Reset the transfer process properties.
|
||||
(tramp-set-connection-property v "process-name" nil)
|
||||
(tramp-set-connection-property v "process-buffer" nil)
|
||||
(when t1 (delete-directory tmpdir 'recurse))))
|
||||
|
||||
;; Handle KEEP-DATE argument.
|
||||
(when keep-date
|
||||
(set-file-times newname (nth 5 (file-attributes dirname))))
|
||||
|
||||
;; Set the mode.
|
||||
(unless keep-date
|
||||
(set-file-modes newname (tramp-default-file-modes dirname)))
|
||||
|
||||
;; When newname did exist, we have wrong cached values.
|
||||
(when t2
|
||||
(with-parsed-tramp-file-name newname nil
|
||||
(tramp-flush-file-property v (file-name-directory localname))
|
||||
(tramp-flush-file-property v localname))))
|
||||
|
||||
;; We must do it file-wise.
|
||||
(t
|
||||
(tramp-run-real-handler
|
||||
'copy-directory (list dirname newname keep-date parents)))))))
|
||||
'copy-directory (list dirname newname keep-date parents))))))))
|
||||
|
||||
(defun tramp-smb-handle-copy-file
|
||||
(filename newname &optional ok-if-already-exists keep-date
|
||||
preserve-uid-gid preserve-selinux-context)
|
||||
"Like `copy-file' for Tramp files.
|
||||
KEEP-DATE is not handled in case NEWNAME resides on an SMB server.
|
||||
KEEP-DATE has no effect in case NEWNAME resides on an SMB server.
|
||||
PRESERVE-UID-GID and PRESERVE-SELINUX-CONTEXT are completely ignored."
|
||||
(setq filename (expand-file-name filename)
|
||||
newname (expand-file-name newname))
|
||||
|
@ -358,40 +495,43 @@ PRESERVE-UID-GID and PRESERVE-SELINUX-CONTEXT are completely ignored."
|
|||
(tramp-dissect-file-name (if (file-remote-p filename) filename newname))
|
||||
0 (format "Copying %s to %s" filename newname)
|
||||
|
||||
(let ((tmpfile (file-local-copy filename)))
|
||||
(if (file-directory-p filename)
|
||||
(tramp-compat-copy-directory filename newname keep-date t t)
|
||||
|
||||
(if tmpfile
|
||||
;; Remote filename.
|
||||
(condition-case err
|
||||
(rename-file tmpfile newname ok-if-already-exists)
|
||||
((error quit)
|
||||
(delete-file tmpfile)
|
||||
(signal (car err) (cdr err))))
|
||||
(let ((tmpfile (file-local-copy filename)))
|
||||
(if tmpfile
|
||||
;; Remote filename.
|
||||
(condition-case err
|
||||
(rename-file tmpfile newname ok-if-already-exists)
|
||||
((error quit)
|
||||
(delete-file tmpfile)
|
||||
(signal (car err) (cdr err))))
|
||||
|
||||
;; Remote newname.
|
||||
(when (file-directory-p newname)
|
||||
(setq newname
|
||||
(expand-file-name (file-name-nondirectory filename) newname)))
|
||||
;; Remote newname.
|
||||
(when (file-directory-p newname)
|
||||
(setq newname
|
||||
(expand-file-name (file-name-nondirectory filename) newname)))
|
||||
|
||||
(with-parsed-tramp-file-name newname nil
|
||||
(when (and (not ok-if-already-exists)
|
||||
(file-exists-p newname))
|
||||
(tramp-error v 'file-already-exists newname))
|
||||
(with-parsed-tramp-file-name newname nil
|
||||
(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)
|
||||
(unless (tramp-smb-get-share v)
|
||||
(tramp-error
|
||||
v 'file-error "Target `%s' must contain a share name" newname))
|
||||
(unless (tramp-smb-send-command
|
||||
v (format "put \"%s\" \"%s\""
|
||||
filename (tramp-smb-get-localname v)))
|
||||
(tramp-error v 'file-error "Cannot copy `%s'" filename))))))
|
||||
;; 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)
|
||||
(unless (tramp-smb-get-share v)
|
||||
(tramp-error
|
||||
v 'file-error "Target `%s' must contain a share name" newname))
|
||||
(unless (tramp-smb-send-command
|
||||
v (format "put \"%s\" \"%s\""
|
||||
filename (tramp-smb-get-localname v)))
|
||||
(tramp-error v 'file-error "Cannot copy `%s'" filename))))))
|
||||
|
||||
;; KEEP-DATE handling.
|
||||
(when keep-date (set-file-times newname (nth 5 (file-attributes filename)))))
|
||||
;; KEEP-DATE handling.
|
||||
(when keep-date
|
||||
(set-file-times newname (nth 5 (file-attributes filename))))))
|
||||
|
||||
(defun tramp-smb-handle-delete-directory (directory &optional recursive)
|
||||
"Like `delete-directory' for Tramp files."
|
||||
|
@ -539,7 +679,7 @@ PRESERVE-UID-GID and PRESERVE-SELINUX-CONTEXT are completely ignored."
|
|||
"Implement `file-attributes' for Tramp files using stat command."
|
||||
(tramp-message
|
||||
vec 5 "file attributes with stat: %s" (tramp-file-name-localname vec))
|
||||
(with-current-buffer (tramp-get-buffer vec)
|
||||
(with-current-buffer (tramp-get-connection-buffer vec)
|
||||
(let* (size id link uid gid atime mtime ctime mode inode)
|
||||
(when (tramp-smb-send-command
|
||||
vec (format "stat \"%s\"" (tramp-smb-get-localname vec)))
|
||||
|
@ -845,44 +985,170 @@ target of the symlink differ."
|
|||
"error with make-symbolic-link, see buffer `%s' for details"
|
||||
(buffer-name))))))
|
||||
|
||||
(defun tramp-smb-handle-process-file
|
||||
(program &optional infile destination display &rest args)
|
||||
"Like `process-file' for Tramp files."
|
||||
;; The implementation is not complete yet.
|
||||
(when (and (numberp destination) (zerop destination))
|
||||
(error "Implementation does not handle immediate return"))
|
||||
|
||||
(with-parsed-tramp-file-name default-directory nil
|
||||
(let* ((name (file-name-nondirectory program))
|
||||
(name1 name)
|
||||
(i 0)
|
||||
input tmpinput outbuf command ret)
|
||||
|
||||
;; Determine input.
|
||||
(when infile
|
||||
(setq infile (expand-file-name infile))
|
||||
(if (tramp-equal-remote default-directory infile)
|
||||
;; INFILE is on the same remote host.
|
||||
(setq input (with-parsed-tramp-file-name infile nil localname))
|
||||
;; INFILE must be copied to remote host.
|
||||
(setq input (tramp-make-tramp-temp-file v)
|
||||
tmpinput (tramp-make-tramp-file-name method user host input))
|
||||
(copy-file infile tmpinput t))
|
||||
;; Transform input into a filename powershell does understand.
|
||||
(setq input (format "//%s%s" host input)))
|
||||
|
||||
;; Determine output.
|
||||
(cond
|
||||
;; Just a buffer.
|
||||
((bufferp destination)
|
||||
(setq outbuf destination))
|
||||
;; A buffer name.
|
||||
((stringp destination)
|
||||
(setq outbuf (get-buffer-create destination)))
|
||||
;; (REAL-DESTINATION ERROR-DESTINATION)
|
||||
((consp destination)
|
||||
;; output.
|
||||
(cond
|
||||
((bufferp (car destination))
|
||||
(setq outbuf (car destination)))
|
||||
((stringp (car destination))
|
||||
(setq outbuf (get-buffer-create (car destination))))
|
||||
((car destination)
|
||||
(setq outbuf (current-buffer))))
|
||||
;; stderr.
|
||||
(tramp-message v 2 "%s" "STDERR not supported"))
|
||||
;; 't
|
||||
(destination
|
||||
(setq outbuf (current-buffer))))
|
||||
|
||||
;; Construct command.
|
||||
(setq command (mapconcat 'identity (cons program args) " ")
|
||||
command (if input
|
||||
(format
|
||||
"get-content %s | & %s"
|
||||
(tramp-smb-shell-quote-argument input) command)
|
||||
(format "& %s" command)))
|
||||
|
||||
(while (get-process name1)
|
||||
;; NAME must be unique as process name.
|
||||
(setq i (1+ i)
|
||||
name1 (format "%s<%d>" name i)))
|
||||
|
||||
;; Set the new process properties.
|
||||
(tramp-set-connection-property v "process-name" name1)
|
||||
(tramp-set-connection-property
|
||||
v "process-buffer"
|
||||
(or outbuf (generate-new-buffer tramp-temp-buffer-name)))
|
||||
|
||||
;; Call it.
|
||||
(condition-case nil
|
||||
(with-current-buffer (tramp-get-connection-buffer v)
|
||||
;; Preserve buffer contents.
|
||||
(narrow-to-region (point-max) (point-max))
|
||||
(tramp-smb-call-winexe v)
|
||||
(when (tramp-smb-get-share v)
|
||||
(tramp-smb-send-command
|
||||
v (format "cd \"//%s%s\"" host (file-name-directory localname))))
|
||||
(tramp-smb-send-command v command)
|
||||
;; Preserve command output.
|
||||
(narrow-to-region (point-max) (point-max))
|
||||
(let ((p (tramp-get-connection-process v)))
|
||||
(tramp-smb-send-command v "exit $lasterrorcode")
|
||||
(while (memq (process-status p) '(run open))
|
||||
(sleep-for 0.1)
|
||||
(setq ret (process-exit-status p))))
|
||||
(delete-region (point-min) (point-max))
|
||||
(widen))
|
||||
|
||||
;; When the user did interrupt, we should do it also. We use
|
||||
;; return code -1 as marker.
|
||||
(quit
|
||||
(setq ret -1))
|
||||
;; Handle errors.
|
||||
(error
|
||||
(setq ret 1)))
|
||||
|
||||
;; We should show the output anyway.
|
||||
(when (and outbuf display) (display-buffer outbuf))
|
||||
|
||||
;; Cleanup. We remove all file cache values for the connection,
|
||||
;; because the remote process could have changed them.
|
||||
(tramp-set-connection-property v "process-name" nil)
|
||||
(tramp-set-connection-property v "process-buffer" nil)
|
||||
(when tmpinput (delete-file tmpinput))
|
||||
(unless outbuf
|
||||
(kill-buffer (tramp-get-connection-property v "process-buffer" nil)))
|
||||
|
||||
;; `process-file-side-effects' has been introduced with GNU
|
||||
;; Emacs 23.2. If set to `nil', no remote file will be changed
|
||||
;; by `program'. If it doesn't exist, we assume its default
|
||||
;; value `t'.
|
||||
(unless (and (boundp 'process-file-side-effects)
|
||||
(not (symbol-value 'process-file-side-effects)))
|
||||
(tramp-flush-directory-property v ""))
|
||||
|
||||
;; Return exit status.
|
||||
(if (equal ret -1)
|
||||
(keyboard-quit)
|
||||
ret))))
|
||||
|
||||
(defun tramp-smb-handle-rename-file
|
||||
(filename newname &optional ok-if-already-exists)
|
||||
"Like `rename-file' for Tramp files."
|
||||
(setq filename (expand-file-name filename)
|
||||
newname (expand-file-name newname))
|
||||
|
||||
(when (and (not ok-if-already-exists)
|
||||
(file-exists-p newname))
|
||||
(tramp-error
|
||||
(tramp-dissect-file-name
|
||||
(if (file-remote-p filename) filename newname))
|
||||
'file-already-exists newname))
|
||||
|
||||
(tramp-with-progress-reporter
|
||||
(tramp-dissect-file-name (if (file-remote-p filename) filename newname))
|
||||
0 (format "Renaming %s to %s" filename newname)
|
||||
|
||||
(let ((tmpfile (file-local-copy filename)))
|
||||
(if (and (tramp-equal-remote filename newname)
|
||||
(string-equal
|
||||
(tramp-smb-get-share (tramp-dissect-file-name filename))
|
||||
(tramp-smb-get-share (tramp-dissect-file-name newname))))
|
||||
;; We can rename directly.
|
||||
(with-parsed-tramp-file-name filename v1
|
||||
(with-parsed-tramp-file-name newname v2
|
||||
|
||||
(if tmpfile
|
||||
;; Remote filename.
|
||||
(condition-case err
|
||||
(rename-file tmpfile newname ok-if-already-exists)
|
||||
((error quit)
|
||||
(delete-file tmpfile)
|
||||
(signal (car err) (cdr err))))
|
||||
;; We must also flush the cache of the directory, because
|
||||
;; `file-attributes' reads the values from there.
|
||||
(tramp-flush-file-property v2 (file-name-directory v2-localname))
|
||||
(tramp-flush-file-property v2 v2-localname)
|
||||
(unless (tramp-smb-get-share v2)
|
||||
(tramp-error
|
||||
v2 'file-error "Target `%s' must contain a share name" newname))
|
||||
(unless (tramp-smb-send-command
|
||||
v2 (format "rename \"%s\" \"%s\""
|
||||
(tramp-smb-get-localname v1)
|
||||
(tramp-smb-get-localname v2)))
|
||||
(tramp-error v2 'file-error "Cannot rename `%s'" filename))))
|
||||
|
||||
;; Remote newname.
|
||||
(when (file-directory-p newname)
|
||||
(setq newname (expand-file-name
|
||||
(file-name-nondirectory filename) newname)))
|
||||
|
||||
(with-parsed-tramp-file-name newname nil
|
||||
(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)
|
||||
(unless (tramp-smb-send-command
|
||||
v (format "put %s \"%s\""
|
||||
filename (tramp-smb-get-localname v)))
|
||||
(tramp-error v 'file-error "Cannot rename `%s'" filename)))))
|
||||
|
||||
(delete-file filename)))
|
||||
;; We must rename via copy.
|
||||
(tramp-compat-copy-file filename newname ok-if-already-exists t t t)
|
||||
(if (file-directory-p filename)
|
||||
(tramp-compat-delete-directory filename 'recursive)
|
||||
(delete-file filename)))))
|
||||
|
||||
(defun tramp-smb-handle-set-file-modes (filename mode)
|
||||
"Like `set-file-modes' for Tramp files."
|
||||
|
@ -896,6 +1162,54 @@ target of the symlink differ."
|
|||
(tramp-error
|
||||
v 'file-error "Error while changing file's mode %s" filename)))))
|
||||
|
||||
;; We use BUFFER also as connection buffer during setup. Because of
|
||||
;; this, its original contents must be saved, and restored once
|
||||
;; connection has been setup.
|
||||
(defun tramp-smb-handle-start-file-process (name buffer program &rest args)
|
||||
"Like `start-file-process' for Tramp files."
|
||||
(with-parsed-tramp-file-name default-directory nil
|
||||
(let ((command (mapconcat 'identity (cons program args) " "))
|
||||
(bmp (and (buffer-live-p buffer) (buffer-modified-p buffer)))
|
||||
(name1 name)
|
||||
(i 0))
|
||||
(unwind-protect
|
||||
(save-excursion
|
||||
(save-restriction
|
||||
(unless buffer
|
||||
;; BUFFER can be nil. We use a temporary buffer.
|
||||
(setq buffer (generate-new-buffer tramp-temp-buffer-name)))
|
||||
(while (get-process name1)
|
||||
;; NAME must be unique as process name.
|
||||
(setq i (1+ i)
|
||||
name1 (format "%s<%d>" name i)))
|
||||
;; Set the new process properties.
|
||||
(tramp-set-connection-property v "process-name" name1)
|
||||
(tramp-set-connection-property v "process-buffer" buffer)
|
||||
;; Activate narrowing in order to save BUFFER contents.
|
||||
(with-current-buffer (tramp-get-connection-buffer v)
|
||||
(let ((buffer-undo-list t))
|
||||
(narrow-to-region (point-max) (point-max))
|
||||
(tramp-smb-call-winexe v)
|
||||
(when (tramp-smb-get-share v)
|
||||
(tramp-smb-send-command
|
||||
v (format
|
||||
"cd \"//%s%s\""
|
||||
host (file-name-directory localname))))
|
||||
(tramp-message v 6 "(%s); exit" command)
|
||||
(tramp-send-string v command)))
|
||||
;; Return value.
|
||||
(tramp-get-connection-process v)))
|
||||
|
||||
;; Save exit.
|
||||
(with-current-buffer (tramp-get-connection-buffer v)
|
||||
(if (string-match tramp-temp-buffer-name (buffer-name))
|
||||
(progn
|
||||
(set-process-buffer (tramp-get-connection-process v) nil)
|
||||
(kill-buffer (current-buffer)))
|
||||
(set-buffer-modified-p bmp)))
|
||||
(tramp-set-connection-property v "process-name" nil)
|
||||
(tramp-set-connection-property v "process-buffer" nil)))))
|
||||
|
||||
(defun tramp-smb-handle-substitute-in-file-name (filename)
|
||||
"Like `handle-substitute-in-file-name' for Tramp files.
|
||||
\"//\" substitutes only in the local filename part. Catches
|
||||
|
@ -999,7 +1313,7 @@ Result is a list of (LOCALNAME MODE SIZE MONTH DAY TIME YEAR)."
|
|||
(with-parsed-tramp-file-name (file-name-as-directory directory) nil
|
||||
(setq localname (or localname "/"))
|
||||
(with-file-property v localname "file-entries"
|
||||
(with-current-buffer (tramp-get-buffer v)
|
||||
(with-current-buffer (tramp-get-connection-buffer v)
|
||||
(let* ((share (tramp-smb-get-share v))
|
||||
(cache (tramp-get-connection-property v "share-cache" nil))
|
||||
res entry)
|
||||
|
@ -1187,7 +1501,7 @@ Result is the list (LOCALNAME MODE SIZE MTIME)."
|
|||
(tramp-get-connection-process vec) "cifs-capabilities"
|
||||
(save-match-data
|
||||
(when (tramp-smb-send-command vec "posix")
|
||||
(with-current-buffer (tramp-get-buffer vec)
|
||||
(with-current-buffer (tramp-get-connection-buffer vec)
|
||||
(goto-char (point-min))
|
||||
(when
|
||||
(re-search-forward "Server supports CIFS capabilities" nil t)
|
||||
|
@ -1216,18 +1530,20 @@ Returns nil if there has been an error message from smbclient."
|
|||
(tramp-send-string vec command)
|
||||
(tramp-smb-wait-for-output vec))
|
||||
|
||||
(defun tramp-smb-maybe-open-connection (vec)
|
||||
(defun tramp-smb-maybe-open-connection (vec &optional argument)
|
||||
"Maybe open a connection to HOST, log 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."
|
||||
connection if a previous connection has died for some reason.
|
||||
If ARGUMENT is non-nil, use it as argument for
|
||||
`tramp-smb-winexe-program', and suppress any checks."
|
||||
(let* ((share (tramp-smb-get-share vec))
|
||||
(buf (tramp-get-buffer vec))
|
||||
(buf (tramp-get-connection-buffer vec))
|
||||
(p (get-buffer-process buf)))
|
||||
|
||||
;; Check whether we still have the same smbclient version.
|
||||
;; Otherwise, we must delete the connection cache, because
|
||||
;; capabilities migh have changed.
|
||||
(unless (processp p)
|
||||
(unless (or argument (processp p))
|
||||
(let ((default-directory (tramp-compat-temporary-file-directory))
|
||||
(command (concat tramp-smb-program " -V")))
|
||||
|
||||
|
@ -1271,9 +1587,10 @@ connection if a previous connection has died for some reason."
|
|||
;; Check whether it is still the same share.
|
||||
(unless
|
||||
(and p (processp p) (memq (process-status p) '(run open))
|
||||
(string-equal
|
||||
share
|
||||
(tramp-get-connection-property p "smb-share" "")))
|
||||
(or argument
|
||||
(string-equal
|
||||
share
|
||||
(tramp-get-connection-property p "smb-share" ""))))
|
||||
|
||||
(save-match-data
|
||||
;; There might be unread output from checking for share names.
|
||||
|
@ -1288,9 +1605,13 @@ connection if a previous connection has died for some reason."
|
|||
(port (tramp-file-name-port vec))
|
||||
args)
|
||||
|
||||
(if share
|
||||
(setq args (list (concat "//" real-host "/" share)))
|
||||
(setq args (list "-g" "-L" real-host )))
|
||||
(cond
|
||||
(argument
|
||||
(setq args (list (concat "//" real-host))))
|
||||
(share
|
||||
(setq args (list (concat "//" real-host "/" share))))
|
||||
(t
|
||||
(setq args (list "-g" "-L" real-host ))))
|
||||
|
||||
(if (not (zerop (length real-user)))
|
||||
(setq args (append args (list "-U" real-user)))
|
||||
|
@ -1300,6 +1621,8 @@ connection if a previous connection has died for some reason."
|
|||
(when port (setq args (append args (list "-p" port))))
|
||||
(when tramp-smb-conf
|
||||
(setq args (append args (list "-s" tramp-smb-conf))))
|
||||
(when argument
|
||||
(setq args (append args (list argument))))
|
||||
|
||||
;; OK, let's go.
|
||||
(tramp-with-progress-reporter
|
||||
|
@ -1313,8 +1636,11 @@ connection if a previous connection has died for some reason."
|
|||
(p (let ((default-directory
|
||||
(tramp-compat-temporary-file-directory)))
|
||||
(apply #'start-process
|
||||
(tramp-buffer-name vec) (tramp-get-buffer vec)
|
||||
tramp-smb-program args))))
|
||||
(tramp-get-connection-name vec)
|
||||
(tramp-get-connection-buffer vec)
|
||||
(if argument
|
||||
tramp-smb-winexe-program tramp-smb-program)
|
||||
args))))
|
||||
|
||||
(tramp-message
|
||||
vec 6 "%s" (mapconcat 'identity (process-command p) " "))
|
||||
|
@ -1325,40 +1651,58 @@ connection if a previous connection has died for some reason."
|
|||
tramp-current-user user
|
||||
tramp-current-host host)
|
||||
|
||||
;; Play login scenario.
|
||||
(tramp-process-actions
|
||||
p vec nil
|
||||
(if share
|
||||
tramp-smb-actions-with-share
|
||||
tramp-smb-actions-without-share))
|
||||
(condition-case err
|
||||
(let (tramp-message-show-message)
|
||||
;; Play login scenario.
|
||||
(tramp-process-actions
|
||||
p vec nil
|
||||
(if (or argument share)
|
||||
tramp-smb-actions-with-share
|
||||
tramp-smb-actions-without-share))
|
||||
|
||||
;; Check server version.
|
||||
(with-current-buffer (tramp-get-connection-buffer vec)
|
||||
(goto-char (point-min))
|
||||
(search-forward-regexp
|
||||
"Domain=\\[[^]]*\\] OS=\\[[^]]*\\] Server=\\[[^]]*\\]" nil t)
|
||||
(let ((smbserver-version (match-string 0)))
|
||||
(unless
|
||||
(string-equal
|
||||
smbserver-version
|
||||
(tramp-get-connection-property
|
||||
vec "smbserver-version" smbserver-version))
|
||||
(tramp-flush-directory-property vec "")
|
||||
(tramp-flush-connection-property vec))
|
||||
(tramp-set-connection-property
|
||||
vec "smbserver-version" smbserver-version)))
|
||||
;; Check server version.
|
||||
(unless argument
|
||||
(with-current-buffer (tramp-get-connection-buffer vec)
|
||||
(goto-char (point-min))
|
||||
(search-forward-regexp tramp-smb-server-version nil t)
|
||||
(let ((smbserver-version (match-string 0)))
|
||||
(unless
|
||||
(string-equal
|
||||
smbserver-version
|
||||
(tramp-get-connection-property
|
||||
vec "smbserver-version" smbserver-version))
|
||||
(tramp-flush-directory-property vec "")
|
||||
(tramp-flush-connection-property vec))
|
||||
(tramp-set-connection-property
|
||||
vec "smbserver-version" smbserver-version))))
|
||||
|
||||
;; Set chunksize. Otherwise, `tramp-send-string' might
|
||||
;; try it itself.
|
||||
(tramp-set-connection-property p "smb-share" share)
|
||||
(tramp-set-connection-property
|
||||
p "chunksize" tramp-chunksize))))))))
|
||||
;; Set chunksize. Otherwise, `tramp-send-string' might
|
||||
;; try it itself.
|
||||
(tramp-set-connection-property p "smb-share" share)
|
||||
(tramp-set-connection-property
|
||||
p "chunksize" tramp-chunksize))
|
||||
|
||||
;; Check for the error reason. If it was due to wrong
|
||||
;; password, reestablish the connection. We cannot
|
||||
;; handle this in `tramp-process-actions', because
|
||||
;; smbclient does not ask for the password, again.
|
||||
(error
|
||||
(with-current-buffer (tramp-get-connection-buffer vec)
|
||||
(goto-char (point-min))
|
||||
(if (search-forward-regexp
|
||||
tramp-smb-wrong-passwd-regexp nil t)
|
||||
;; Disable `auth-source' and `password-cache'.
|
||||
(let (auth-sources)
|
||||
(tramp-cleanup vec)
|
||||
(tramp-smb-maybe-open-connection vec argument))
|
||||
;; Propagate the error.
|
||||
(signal (car err) (cdr err)))))))))))))
|
||||
|
||||
;; We don't use timeouts. If needed, the caller shall wrap around.
|
||||
(defun tramp-smb-wait-for-output (vec)
|
||||
"Wait for output from smbclient command.
|
||||
Returns nil if an error message has appeared."
|
||||
(with-current-buffer (tramp-get-buffer vec)
|
||||
(with-current-buffer (tramp-get-connection-buffer vec)
|
||||
(let ((p (get-buffer-process (current-buffer)))
|
||||
(found (progn (goto-char (point-min))
|
||||
(re-search-forward tramp-smb-prompt nil t)))
|
||||
|
@ -1392,10 +1736,68 @@ Returns nil if an error message has appeared."
|
|||
(goto-char (point-min))
|
||||
(setq found (re-search-forward tramp-smb-prompt nil t)))
|
||||
|
||||
;; Return value is whether no error message has appeared.
|
||||
(tramp-message vec 6 "\n%s" (buffer-string))
|
||||
|
||||
;; Remove prompt.
|
||||
(when found
|
||||
(goto-char (point-max))
|
||||
(re-search-backward tramp-smb-prompt nil t)
|
||||
(delete-region (point) (point-max)))
|
||||
|
||||
;; Return value is whether no error message has appeared.
|
||||
(not err))))
|
||||
|
||||
(defun tramp-smb-kill-winexe-function ()
|
||||
"Send SIGKILL to the winexe process."
|
||||
(ignore-errors
|
||||
(let ((p (get-buffer-process (current-buffer))))
|
||||
(when (and p (processp p) (memq (process-status p) '(run open)))
|
||||
(signal-process (process-id p) 'SIGINT)))))
|
||||
|
||||
(defun tramp-smb-call-winexe (vec)
|
||||
"Apply a remote command, if possible, using `tramp-smb-winexe-program'."
|
||||
|
||||
;; We call `tramp-get-buffer' in order to get a debug buffer for
|
||||
;; messages.
|
||||
(tramp-get-buffer vec)
|
||||
|
||||
;; Check for program.
|
||||
(unless (let ((default-directory
|
||||
(tramp-compat-temporary-file-directory)))
|
||||
(executable-find tramp-smb-winexe-program))
|
||||
(tramp-error
|
||||
vec 'file-error "Cannot find program: %s" tramp-smb-winexe-program))
|
||||
|
||||
;; winexe does not supports ports.
|
||||
(when (tramp-file-name-port vec)
|
||||
(tramp-error vec 'file-error "Port not supported for remote processes"))
|
||||
|
||||
(tramp-smb-maybe-open-connection
|
||||
vec
|
||||
(format
|
||||
"%s %s"
|
||||
tramp-smb-winexe-shell-command tramp-smb-winexe-shell-command-switch))
|
||||
|
||||
(set (make-local-variable 'kill-buffer-hook)
|
||||
'(tramp-smb-kill-winexe-function))
|
||||
|
||||
;; Suppress "^M". Shouldn't we specify utf8?
|
||||
(set-process-coding-system (tramp-get-connection-process vec) 'raw-text-dos)
|
||||
|
||||
;; Set width to 128. This avoids mixing prompt and long error messages.
|
||||
(tramp-smb-send-command vec "$rawui = (Get-Host).UI.RawUI")
|
||||
(tramp-smb-send-command vec "$bufsize = $rawui.BufferSize")
|
||||
(tramp-smb-send-command vec "$winsize = $rawui.WindowSize")
|
||||
(tramp-smb-send-command vec "$bufsize.Width = 128")
|
||||
(tramp-smb-send-command vec "$winsize.Width = 128")
|
||||
(tramp-smb-send-command vec "$rawui.BufferSize = $bufsize")
|
||||
(tramp-smb-send-command vec "$rawui.WindowSize = $winsize"))
|
||||
|
||||
(defun tramp-smb-shell-quote-argument (s)
|
||||
"Similar to `shell-quote-argument', but uses windows cmd syntax."
|
||||
(let ((system-type 'ms-dos))
|
||||
(shell-quote-argument s)))
|
||||
|
||||
(add-hook 'tramp-unload-hook
|
||||
(lambda ()
|
||||
(unload-feature 'tramp-smb 'force)))
|
||||
|
@ -1404,12 +1806,9 @@ Returns nil if an error message has appeared."
|
|||
|
||||
;;; TODO:
|
||||
|
||||
;; * Error handling in case password is wrong.
|
||||
;; * Return more comprehensive file permission string.
|
||||
;; * Try to remove the inclusion of dummy "" directory. Seems to be at
|
||||
;; several places, especially in `tramp-smb-handle-insert-directory'.
|
||||
;; * (RMS) Use unwind-protect to clean up the state so as to make the state
|
||||
;; regular again.
|
||||
;; * Ignore case in file names.
|
||||
|
||||
;;; tramp-smb.el ends here
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -31,7 +31,7 @@
|
|||
;; should be changed only there.
|
||||
|
||||
;;;###tramp-autoload
|
||||
(defconst tramp-version "2.2.3-24.1"
|
||||
(defconst tramp-version "2.2.6-pre"
|
||||
"This version of Tramp.")
|
||||
|
||||
;;;###tramp-autoload
|
||||
|
@ -44,7 +44,7 @@
|
|||
(= emacs-major-version 21)
|
||||
(>= emacs-minor-version 4)))
|
||||
"ok"
|
||||
(format "Tramp 2.2.3-24.1 is not fit for %s"
|
||||
(format "Tramp 2.2.6-pre is not fit for %s"
|
||||
(when (string-match "^.*$" (emacs-version))
|
||||
(match-string 0 (emacs-version)))))))
|
||||
(unless (string-match "\\`ok\\'" x) (error "%s" x)))
|
||||
|
|
Loading…
Add table
Reference in a new issue