LCOV - code coverage report
Current view: top level - lisp/net - tramp-smb.el (source / functions) Hit Total Coverage
Test: tramp-tests.info Lines: 6 1115 0.5 %
Date: 2017-08-27 09:44:50 Functions: 2 52 3.8 %

          Line data    Source code
       1             : ;;; tramp-smb.el --- Tramp access functions for SMB servers  -*- lexical-binding:t -*-
       2             : 
       3             : ;; Copyright (C) 2002-2017 Free Software Foundation, Inc.
       4             : 
       5             : ;; Author: Michael Albinus <michael.albinus@gmx.de>
       6             : ;; Keywords: comm, processes
       7             : ;; Package: tramp
       8             : 
       9             : ;; This file is part of GNU Emacs.
      10             : 
      11             : ;; GNU Emacs is free software: you can redistribute it and/or modify
      12             : ;; it under the terms of the GNU General Public License as published by
      13             : ;; the Free Software Foundation, either version 3 of the License, or
      14             : ;; (at your option) any later version.
      15             : 
      16             : ;; GNU Emacs is distributed in the hope that it will be useful,
      17             : ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
      18             : ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      19             : ;; GNU General Public License for more details.
      20             : 
      21             : ;; You should have received a copy of the GNU General Public License
      22             : ;; along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
      23             : 
      24             : ;;; Commentary:
      25             : 
      26             : ;; Access functions for SMB servers like SAMBA or M$ Windows from Tramp.
      27             : 
      28             : ;;; Code:
      29             : 
      30             : (require 'tramp)
      31             : 
      32             : ;; Define SMB method ...
      33             : ;;;###tramp-autoload
      34             : (defconst tramp-smb-method "smb"
      35             :   "Method to connect SAMBA and M$ SMB servers.")
      36             : 
      37             : ;; ... and add it to the method list.
      38             : ;;;###tramp-autoload
      39             : (unless (memq system-type '(cygwin windows-nt))
      40             :   (add-to-list 'tramp-methods
      41             :     `(,tramp-smb-method
      42             :       ;; We define an empty command, because `tramp-smb-call-winexe'
      43             :       ;; opens already the powershell.  Used in `tramp-handle-shell-command'.
      44             :       (tramp-remote-shell "")
      45             :       ;; This is just a guess.  We don't know whether the share "C$"
      46             :       ;; is available for public use, and whether the user has write
      47             :       ;; access.
      48             :       (tramp-tmpdir "/C$/Temp")
      49             :       ;; Another guess.  We might implement a better check later on.
      50             :       (tramp-case-insensitive t))))
      51             : 
      52             : ;; Add a default for `tramp-default-user-alist'. Rule: For the SMB method,
      53             : ;; the anonymous user is chosen.
      54             : ;;;###tramp-autoload
      55             : (add-to-list 'tramp-default-user-alist
      56             :              `(,(concat "\\`" tramp-smb-method "\\'") nil nil))
      57             : 
      58             : ;; Add completion function for SMB method.
      59             : ;;;###tramp-autoload
      60             : (eval-after-load 'tramp
      61             :   '(tramp-set-completion-function
      62             :     tramp-smb-method
      63             :     '((tramp-parse-netrc "~/.netrc"))))
      64             : 
      65             : ;;;###tramp-autoload
      66             : (defcustom tramp-smb-program "smbclient"
      67             :   "Name of SMB client to run."
      68             :   :group 'tramp
      69             :   :type 'string
      70             :   :require 'tramp)
      71             : 
      72             : ;;;###tramp-autoload
      73             : (defcustom tramp-smb-acl-program "smbcacls"
      74             :   "Name of SMB acls to run."
      75             :   :group 'tramp
      76             :   :type 'string
      77             :   :version "24.4"
      78             :   :require 'tramp)
      79             : 
      80             : ;;;###tramp-autoload
      81             : (defcustom tramp-smb-conf "/dev/null"
      82             :   "Path of the smb.conf file.
      83             : If it is nil, no smb.conf will be added to the `tramp-smb-program'
      84             : call, letting the SMB client use the default one."
      85             :   :group 'tramp
      86             :   :type '(choice (const nil) (file :must-match t))
      87             :   :require 'tramp)
      88             : 
      89             : (defvar tramp-smb-version nil
      90             :   "Version string of the SMB client.")
      91             : 
      92             : (defconst tramp-smb-server-version
      93             :   "Domain=\\[[^]]*\\] OS=\\[[^]]*\\] Server=\\[[^]]*\\]"
      94             :   "Regexp of SMB server identification.")
      95             : 
      96             : (defconst tramp-smb-prompt "^\\(smb:\\|PS\\) .+> \\|^\\s-+Server\\s-+Comment$"
      97             :   "Regexp used as prompt in smbclient or powershell.")
      98             : 
      99             : (defconst tramp-smb-wrong-passwd-regexp
     100             :   (regexp-opt
     101             :    '("NT_STATUS_LOGON_FAILURE"
     102             :      "NT_STATUS_WRONG_PASSWORD"))
     103             :   "Regexp for login error strings of SMB servers.")
     104             : 
     105             : (defconst tramp-smb-errors
     106             :   (mapconcat
     107             :    'identity
     108             :    `(;; Connection error / timeout / unknown command.
     109             :      "Connection\\( to \\S-+\\)? failed"
     110             :      "Read from server failed, maybe it closed the connection"
     111             :      "Call timed out: server did not respond"
     112             :      "\\S-+: command not found"
     113             :      "Server doesn't support UNIX CIFS calls"
     114             :      ,(regexp-opt
     115             :        '(;; Samba.
     116             :          "ERRDOS"
     117             :          "ERRHRD"
     118             :          "ERRSRV"
     119             :          "ERRbadfile"
     120             :          "ERRbadpw"
     121             :          "ERRfilexists"
     122             :          "ERRnoaccess"
     123             :          "ERRnomem"
     124             :          "ERRnosuchshare"
     125             :          ;; Windows 4.0 (Windows NT), Windows 5.0 (Windows 2000),
     126             :          ;; Windows 5.1 (Windows XP), Windows 5.2 (Windows Server 2003),
     127             :          ;; Windows 6.0 (Windows Vista), Windows 6.1 (Windows 7),
     128             :          ;; Windows 6.3 (Windows Server 2012, Windows 10).
     129             :          "NT_STATUS_ACCESS_DENIED"
     130             :          "NT_STATUS_ACCOUNT_LOCKED_OUT"
     131             :          "NT_STATUS_BAD_NETWORK_NAME"
     132             :          "NT_STATUS_CANNOT_DELETE"
     133             :          "NT_STATUS_CONNECTION_REFUSED"
     134             :          "NT_STATUS_DIRECTORY_NOT_EMPTY"
     135             :          "NT_STATUS_DUPLICATE_NAME"
     136             :          "NT_STATUS_FILE_IS_A_DIRECTORY"
     137             :          "NT_STATUS_HOST_UNREACHABLE"
     138             :          "NT_STATUS_IMAGE_ALREADY_LOADED"
     139             :          "NT_STATUS_INVALID_LEVEL"
     140             :          "NT_STATUS_INVALID_PARAMETER_MIX"
     141             :          "NT_STATUS_IO_TIMEOUT"
     142             :          "NT_STATUS_LOGON_FAILURE"
     143             :          "NT_STATUS_NETWORK_ACCESS_DENIED"
     144             :          "NT_STATUS_NOT_IMPLEMENTED"
     145             :          "NT_STATUS_NO_LOGON_SERVERS"
     146             :          "NT_STATUS_NO_SUCH_FILE"
     147             :          "NT_STATUS_NO_SUCH_USER"
     148             :          "NT_STATUS_OBJECT_NAME_COLLISION"
     149             :          "NT_STATUS_OBJECT_NAME_INVALID"
     150             :          "NT_STATUS_OBJECT_NAME_NOT_FOUND"
     151             :          "NT_STATUS_PASSWORD_MUST_CHANGE"
     152             :          "NT_STATUS_SHARING_VIOLATION"
     153             :          "NT_STATUS_TRUSTED_RELATIONSHIP_FAILURE"
     154             :          "NT_STATUS_UNSUCCESSFUL"
     155             :          "NT_STATUS_WRONG_PASSWORD")))
     156             :    "\\|")
     157             :   "Regexp for possible error strings of SMB servers.
     158             : Used instead of analyzing error codes of commands.")
     159             : 
     160             : (defconst tramp-smb-actions-with-share
     161             :   '((tramp-smb-prompt tramp-action-succeed)
     162             :     (tramp-password-prompt-regexp tramp-action-password)
     163             :     (tramp-wrong-passwd-regexp tramp-action-permission-denied)
     164             :     (tramp-smb-errors tramp-action-permission-denied)
     165             :     (tramp-process-alive-regexp tramp-action-process-alive))
     166             :   "List of pattern/action pairs.
     167             : This list is used for login to SMB servers.
     168             : 
     169             : See `tramp-actions-before-shell' for more info.")
     170             : 
     171             : (defconst tramp-smb-actions-without-share
     172             :   '((tramp-password-prompt-regexp tramp-action-password)
     173             :     (tramp-wrong-passwd-regexp tramp-action-permission-denied)
     174             :     (tramp-smb-errors tramp-action-permission-denied)
     175             :     (tramp-process-alive-regexp tramp-action-out-of-band))
     176             :   "List of pattern/action pairs.
     177             : This list is used for login to SMB servers.
     178             : 
     179             : See `tramp-actions-before-shell' for more info.")
     180             : 
     181             : (defconst tramp-smb-actions-with-tar
     182             :   '((tramp-password-prompt-regexp tramp-action-password)
     183             :     (tramp-wrong-passwd-regexp tramp-action-permission-denied)
     184             :     (tramp-smb-errors tramp-action-permission-denied)
     185             :     (tramp-process-alive-regexp tramp-smb-action-with-tar))
     186             :   "List of pattern/action pairs.
     187             : This list is used for tar-like copy of directories.
     188             : 
     189             : See `tramp-actions-before-shell' for more info.")
     190             : 
     191             : (defconst tramp-smb-actions-get-acl
     192             :   '((tramp-password-prompt-regexp tramp-action-password)
     193             :     (tramp-wrong-passwd-regexp tramp-action-permission-denied)
     194             :     (tramp-smb-errors tramp-action-permission-denied)
     195             :     (tramp-process-alive-regexp tramp-smb-action-get-acl))
     196             :   "List of pattern/action pairs.
     197             : This list is used for smbcacls actions.
     198             : 
     199             : See `tramp-actions-before-shell' for more info.")
     200             : 
     201             : (defconst tramp-smb-actions-set-acl
     202             :   '((tramp-password-prompt-regexp tramp-action-password)
     203             :     (tramp-wrong-passwd-regexp tramp-action-permission-denied)
     204             :     (tramp-smb-errors tramp-action-permission-denied)
     205             :     (tramp-process-alive-regexp tramp-smb-action-set-acl))
     206             :   "List of pattern/action pairs.
     207             : This list is used for smbcacls actions.
     208             : 
     209             : See `tramp-actions-before-shell' for more info.")
     210             : 
     211             : ;; New handlers should be added here.
     212             : ;;;###tramp-autoload
     213             : (defconst tramp-smb-file-name-handler-alist
     214             :   '(;; `access-file' performed by default handler.
     215             :     (add-name-to-file . tramp-smb-handle-add-name-to-file)
     216             :     ;; `byte-compiler-base-file-name' performed by default handler.
     217             :     (copy-directory . tramp-smb-handle-copy-directory)
     218             :     (copy-file . tramp-smb-handle-copy-file)
     219             :     (delete-directory . tramp-smb-handle-delete-directory)
     220             :     (delete-file . tramp-smb-handle-delete-file)
     221             :     ;; `diff-latest-backup-file' performed by default handler.
     222             :     (directory-file-name . tramp-handle-directory-file-name)
     223             :     (directory-files . tramp-smb-handle-directory-files)
     224             :     (directory-files-and-attributes
     225             :      . tramp-handle-directory-files-and-attributes)
     226             :     (dired-compress-file . ignore)
     227             :     (dired-uncache . tramp-handle-dired-uncache)
     228             :     (expand-file-name . tramp-smb-handle-expand-file-name)
     229             :     (file-accessible-directory-p . tramp-smb-handle-file-directory-p)
     230             :     (file-acl . tramp-smb-handle-file-acl)
     231             :     (file-attributes . tramp-smb-handle-file-attributes)
     232             :     (file-directory-p .  tramp-smb-handle-file-directory-p)
     233             :     (file-file-equal-p . tramp-handle-file-equal-p)
     234             :     (file-executable-p . tramp-handle-file-exists-p)
     235             :     (file-exists-p . tramp-handle-file-exists-p)
     236             :     (file-in-directory-p . tramp-handle-file-in-directory-p)
     237             :     (file-local-copy . tramp-smb-handle-file-local-copy)
     238             :     (file-modes . tramp-handle-file-modes)
     239             :     (file-name-all-completions . tramp-smb-handle-file-name-all-completions)
     240             :     (file-name-as-directory . tramp-handle-file-name-as-directory)
     241             :     (file-name-case-insensitive-p . tramp-handle-file-name-case-insensitive-p)
     242             :     (file-name-completion . tramp-handle-file-name-completion)
     243             :     (file-name-directory . tramp-handle-file-name-directory)
     244             :     (file-name-nondirectory . tramp-handle-file-name-nondirectory)
     245             :     ;; `file-name-sans-versions' performed by default handler.
     246             :     (file-newer-than-file-p . tramp-handle-file-newer-than-file-p)
     247             :     (file-notify-add-watch . tramp-handle-file-notify-add-watch)
     248             :     (file-notify-rm-watch . tramp-handle-file-notify-rm-watch)
     249             :     (file-notify-valid-p . tramp-handle-file-notify-valid-p)
     250             :     (file-ownership-preserved-p . ignore)
     251             :     (file-readable-p . tramp-handle-file-exists-p)
     252             :     (file-regular-p . tramp-handle-file-regular-p)
     253             :     (file-remote-p . tramp-handle-file-remote-p)
     254             :     ;; `file-selinux-context' performed by default handler.
     255             :     (file-symlink-p . tramp-handle-file-symlink-p)
     256             :     ;; `file-truename' performed by default handler.
     257             :     (file-writable-p . tramp-smb-handle-file-writable-p)
     258             :     (find-backup-file-name . tramp-handle-find-backup-file-name)
     259             :     ;; `find-file-noselect' performed by default handler.
     260             :     ;; `get-file-buffer' performed by default handler.
     261             :     (insert-directory . tramp-smb-handle-insert-directory)
     262             :     (insert-file-contents . tramp-handle-insert-file-contents)
     263             :     (load . tramp-handle-load)
     264             :     (make-auto-save-file-name . tramp-handle-make-auto-save-file-name)
     265             :     (make-directory . tramp-smb-handle-make-directory)
     266             :     (make-directory-internal . tramp-smb-handle-make-directory-internal)
     267             :     (make-nearby-temp-file . tramp-handle-make-nearby-temp-file)
     268             :     (make-symbolic-link . tramp-smb-handle-make-symbolic-link)
     269             :     (process-file . tramp-smb-handle-process-file)
     270             :     (rename-file . tramp-smb-handle-rename-file)
     271             :     (set-file-acl . tramp-smb-handle-set-file-acl)
     272             :     (set-file-modes . tramp-smb-handle-set-file-modes)
     273             :     (set-file-selinux-context . ignore)
     274             :     (set-file-times . ignore)
     275             :     (set-visited-file-modtime . tramp-handle-set-visited-file-modtime)
     276             :     (shell-command . tramp-handle-shell-command)
     277             :     (start-file-process . tramp-smb-handle-start-file-process)
     278             :     (substitute-in-file-name . tramp-smb-handle-substitute-in-file-name)
     279             :     (temporary-file-directory . tramp-handle-temporary-file-directory)
     280             :     (unhandled-file-name-directory . ignore)
     281             :     (vc-registered . ignore)
     282             :     (verify-visited-file-modtime . tramp-handle-verify-visited-file-modtime)
     283             :     (write-region . tramp-smb-handle-write-region))
     284             :   "Alist of handler functions for Tramp SMB method.
     285             : Operations not mentioned here will be handled by the default Emacs primitives.")
     286             : 
     287             : ;; Options for remote processes via winexe.
     288             : ;;;###tramp-autoload
     289             : (defcustom tramp-smb-winexe-program "winexe"
     290             :   "Name of winexe client to run.
     291             : If it isn't found in the local $PATH, the absolute path of winexe
     292             : shall be given.  This is needed for remote processes."
     293             :   :group 'tramp
     294             :   :type 'string
     295             :   :version "24.3"
     296             :   :require 'tramp)
     297             : 
     298             : ;;;###tramp-autoload
     299             : (defcustom tramp-smb-winexe-shell-command "powershell.exe"
     300             :   "Shell to be used for processes on remote machines.
     301             : This must be Powershell V2 compatible."
     302             :   :group 'tramp
     303             :   :type 'string
     304             :   :version "24.3"
     305             :   :require 'tramp)
     306             : 
     307             : ;;;###tramp-autoload
     308             : (defcustom tramp-smb-winexe-shell-command-switch "-file -"
     309             :   "Command switch used together with `tramp-smb-winexe-shell-command'.
     310             : This can be used to disable echo etc."
     311             :   :group 'tramp
     312             :   :type 'string
     313             :   :version "24.3"
     314             :   :require 'tramp)
     315             : 
     316             : ;; It must be a `defsubst' in order to push the whole code into
     317             : ;; tramp-loaddefs.el.  Otherwise, there would be recursive autoloading.
     318             : ;;;###tramp-autoload
     319             : (defsubst tramp-smb-file-name-p (filename)
     320             :   "Check if it's a filename for SMB servers."
     321       44927 :   (string= (tramp-file-name-method (tramp-dissect-file-name filename))
     322       44927 :            tramp-smb-method))
     323             : 
     324             : ;;;###tramp-autoload
     325             : (defun tramp-smb-file-name-handler (operation &rest args)
     326             :   "Invoke the SMB related OPERATION.
     327             : First arg specifies the OPERATION, second arg is a list of arguments to
     328             : pass to the OPERATION."
     329           1 :   (let ((fn (assoc operation tramp-smb-file-name-handler-alist)))
     330           1 :     (if fn
     331           1 :         (save-match-data (apply (cdr fn) args))
     332           1 :       (tramp-run-real-handler operation args))))
     333             : 
     334             : ;;;###tramp-autoload
     335             : (unless (memq system-type '(cygwin windows-nt))
     336             :   (tramp-register-foreign-file-name-handler
     337             :    'tramp-smb-file-name-p 'tramp-smb-file-name-handler))
     338             : 
     339             : ;; File name primitives.
     340             : 
     341             : (defun tramp-smb-handle-add-name-to-file
     342             :   (filename newname &optional ok-if-already-exists)
     343             :   "Like `add-name-to-file' for Tramp files."
     344           0 :   (unless (tramp-equal-remote filename newname)
     345           0 :     (with-parsed-tramp-file-name
     346           0 :         (if (tramp-tramp-file-p filename) filename newname) nil
     347           0 :       (tramp-error
     348           0 :        v 'file-error
     349             :        "add-name-to-file: %s"
     350           0 :        "only implemented for same method, same user, same host")))
     351           0 :   (with-parsed-tramp-file-name filename v1
     352           0 :     (with-parsed-tramp-file-name newname v2
     353           0 :       (when (file-directory-p filename)
     354           0 :         (tramp-error
     355           0 :          v2 'file-error
     356           0 :          "add-name-to-file: %s must not be a directory" filename))
     357           0 :       (when (and (not ok-if-already-exists)
     358           0 :                  (file-exists-p newname)
     359           0 :                  (not (numberp ok-if-already-exists))
     360           0 :                  (y-or-n-p
     361           0 :                   (format
     362             :                    "File %s already exists; make it a new name anyway? "
     363           0 :                    newname)))
     364           0 :         (tramp-error
     365           0 :          v2 'file-error
     366           0 :          "add-name-to-file: file %s already exists" newname))
     367             :       ;; We must also flush the cache of the directory, because
     368             :       ;; `file-attributes' reads the values from there.
     369           0 :       (tramp-flush-file-property v2 (file-name-directory v2-localname))
     370           0 :       (tramp-flush-file-property v2 v2-localname)
     371           0 :       (unless
     372           0 :           (tramp-smb-send-command
     373           0 :            v1
     374           0 :            (format
     375             :             "%s \"%s\" \"%s\""
     376           0 :             (if (tramp-smb-get-cifs-capabilities v1) "link" "hardlink")
     377           0 :             (tramp-smb-get-localname v1)
     378           0 :             (tramp-smb-get-localname v2)))
     379           0 :         (tramp-error
     380           0 :          v2 'file-error
     381             :          "error with add-name-to-file, see buffer `%s' for details"
     382           0 :          (buffer-name))))))
     383             : 
     384             : (defun tramp-smb-action-with-tar (proc vec)
     385             :   "Untar from connection buffer."
     386           0 :   (if (not (process-live-p proc))
     387           0 :       (throw 'tramp-action 'process-died)
     388             : 
     389           0 :     (with-current-buffer (tramp-get-connection-buffer vec)
     390           0 :       (goto-char (point-min))
     391           0 :       (when (search-forward-regexp tramp-smb-server-version nil t)
     392             :         ;; There might be a hidden password prompt.
     393           0 :         (widen)
     394           0 :         (forward-line)
     395           0 :         (tramp-message vec 6 (buffer-substring (point-min) (point)))
     396           0 :         (delete-region (point-min) (point))
     397           0 :         (throw 'tramp-action 'ok)))))
     398             : 
     399             : (defun tramp-smb-handle-copy-directory
     400             :   (dirname newname &optional keep-date parents copy-contents)
     401             :   "Like `copy-directory' for Tramp files."
     402           0 :   (if copy-contents
     403             :       ;; We must do it file-wise.
     404           0 :       (tramp-run-real-handler
     405           0 :        'copy-directory (list dirname newname keep-date parents copy-contents))
     406             : 
     407           0 :     (setq dirname (expand-file-name dirname)
     408           0 :           newname (expand-file-name newname))
     409           0 :     (let ((t1 (tramp-tramp-file-p dirname))
     410           0 :           (t2 (tramp-tramp-file-p newname)))
     411           0 :       (with-parsed-tramp-file-name (if t1 dirname newname) nil
     412           0 :         (with-tramp-progress-reporter
     413           0 :             v 0 (format "Copying %s to %s" dirname newname)
     414           0 :           (cond
     415             :            ;; We must use a local temporary directory.
     416           0 :            ((and t1 t2)
     417           0 :             (let ((tmpdir
     418           0 :                    (make-temp-name
     419           0 :                     (expand-file-name
     420           0 :                      tramp-temp-name-prefix
     421           0 :                      (tramp-compat-temporary-file-directory)))))
     422           0 :               (unwind-protect
     423           0 :                   (progn
     424           0 :                     (make-directory tmpdir)
     425           0 :                     (copy-directory dirname tmpdir keep-date 'parents)
     426           0 :                     (copy-directory
     427           0 :                      (expand-file-name (file-name-nondirectory dirname) tmpdir)
     428           0 :                      newname keep-date parents))
     429           0 :                 (delete-directory tmpdir 'recursive))))
     430             : 
     431             :            ;; We can copy recursively.
     432           0 :            ((and (or t1 t2) (tramp-smb-get-cifs-capabilities v))
     433           0 :             (when (and (file-directory-p newname)
     434           0 :                        (not (string-equal (file-name-nondirectory dirname)
     435           0 :                                           (file-name-nondirectory newname))))
     436           0 :               (setq newname
     437           0 :                     (expand-file-name
     438           0 :                      (file-name-nondirectory dirname) newname))
     439           0 :               (if t2 (setq v (tramp-dissect-file-name newname))))
     440           0 :             (if (not (file-directory-p newname))
     441           0 :                 (make-directory newname parents))
     442             : 
     443             :             ;; Set variables for computing the prompt for reading password.
     444           0 :             (setq tramp-current-method method
     445           0 :                   tramp-current-user user
     446           0 :                   tramp-current-domain domain
     447           0 :                   tramp-current-host host
     448           0 :                   tramp-current-port port)
     449             : 
     450           0 :             (let* ((share (tramp-smb-get-share v))
     451           0 :                    (localname (file-name-as-directory
     452           0 :                                (replace-regexp-in-string
     453           0 :                                 "\\\\" "/" (tramp-smb-get-localname v))))
     454           0 :                    (tmpdir    (make-temp-name
     455           0 :                                (expand-file-name
     456           0 :                                 tramp-temp-name-prefix
     457           0 :                                 (tramp-compat-temporary-file-directory))))
     458           0 :                    (args      (list (concat "//" host "/" share) "-E")))
     459             : 
     460           0 :               (if (not (zerop (length user)))
     461           0 :                   (setq args (append args (list "-U" user)))
     462           0 :                 (setq args (append args (list "-N"))))
     463             : 
     464           0 :               (when domain (setq args (append args (list "-W" domain))))
     465           0 :               (when port   (setq args (append args (list "-p" port))))
     466           0 :               (when tramp-smb-conf
     467           0 :                 (setq args (append args (list "-s" tramp-smb-conf))))
     468           0 :               (setq args
     469           0 :                     (if t1
     470             :                         ;; Source is remote.
     471           0 :                         (append args
     472           0 :                                 (list "-D" (tramp-unquote-shell-quote-argument
     473           0 :                                             localname)
     474           0 :                                       "-c" (shell-quote-argument "tar qc - *")
     475             :                                       "|" "tar" "xfC" "-"
     476           0 :                                       (tramp-unquote-shell-quote-argument
     477           0 :                                        tmpdir)))
     478             :                       ;; Target is remote.
     479           0 :                       (append (list "tar" "cfC" "-"
     480           0 :                                     (tramp-unquote-shell-quote-argument dirname)
     481           0 :                                     "." "|")
     482           0 :                               args
     483           0 :                               (list "-D" (tramp-unquote-shell-quote-argument
     484           0 :                                           localname)
     485           0 :                                     "-c" (shell-quote-argument "tar qx -")))))
     486             : 
     487           0 :               (unwind-protect
     488           0 :                   (with-temp-buffer
     489             :                     ;; Set the transfer process properties.
     490           0 :                     (tramp-set-connection-property
     491           0 :                      v "process-name" (buffer-name (current-buffer)))
     492           0 :                     (tramp-set-connection-property
     493           0 :                      v "process-buffer" (current-buffer))
     494             : 
     495           0 :                     (when t1
     496             :                       ;; The smbclient tar command creates always
     497             :                       ;; complete paths.  We must emulate the
     498             :                       ;; directory structure, and symlink to the real
     499             :                       ;; target.
     500           0 :                       (make-directory
     501           0 :                        (expand-file-name
     502           0 :                         ".." (concat tmpdir localname))
     503           0 :                        'parents)
     504           0 :                       (make-symbolic-link
     505           0 :                        newname (directory-file-name (concat tmpdir localname))))
     506             : 
     507             :                     ;; Use an asynchronous processes.  By this,
     508             :                     ;; password can be handled.
     509           0 :                     (let* ((default-directory tmpdir)
     510           0 :                            (p (apply
     511             :                                'start-process
     512           0 :                                (tramp-get-connection-name v)
     513           0 :                                (tramp-get-connection-buffer v)
     514           0 :                                tramp-smb-program args)))
     515             : 
     516           0 :                       (tramp-message
     517           0 :                        v 6 "%s" (mapconcat 'identity (process-command p) " "))
     518           0 :                       (tramp-set-connection-property p "vector" v)
     519           0 :                       (process-put p 'adjust-window-size-function 'ignore)
     520           0 :                       (set-process-query-on-exit-flag p nil)
     521           0 :                       (tramp-process-actions p v nil tramp-smb-actions-with-tar)
     522             : 
     523           0 :                       (while (process-live-p p)
     524           0 :                         (sit-for 0.1))
     525           0 :                       (tramp-message v 6 "\n%s" (buffer-string))))
     526             : 
     527             :                 ;; Reset the transfer process properties.
     528           0 :                 (tramp-set-connection-property v "process-name" nil)
     529           0 :                 (tramp-set-connection-property v "process-buffer" nil)
     530           0 :                 (when t1 (delete-directory tmpdir 'recurse))))
     531             : 
     532             :             ;; Handle KEEP-DATE argument.
     533           0 :             (when keep-date
     534           0 :               (set-file-times
     535           0 :                newname
     536           0 :                (tramp-compat-file-attribute-modification-time
     537           0 :                 (file-attributes dirname))))
     538             : 
     539             :             ;; Set the mode.
     540           0 :             (unless keep-date
     541           0 :               (set-file-modes newname (tramp-default-file-modes dirname)))
     542             : 
     543             :             ;; When newname did exist, we have wrong cached values.
     544           0 :             (when t2
     545           0 :               (with-parsed-tramp-file-name newname nil
     546           0 :                 (tramp-flush-file-property v (file-name-directory localname))
     547           0 :                 (tramp-flush-file-property v localname))))
     548             : 
     549             :            ;; We must do it file-wise.
     550             :            (t
     551           0 :             (tramp-run-real-handler
     552           0 :              'copy-directory (list dirname newname keep-date parents)))))))))
     553             : 
     554             : (defun tramp-smb-handle-copy-file
     555             :   (filename newname &optional ok-if-already-exists keep-date
     556             :    _preserve-uid-gid _preserve-extended-attributes)
     557             :   "Like `copy-file' for Tramp files.
     558             : KEEP-DATE has no effect in case NEWNAME resides on an SMB server.
     559             : PRESERVE-UID-GID and PRESERVE-EXTENDED-ATTRIBUTES are completely ignored."
     560           0 :   (setq filename (expand-file-name filename)
     561           0 :         newname (expand-file-name newname))
     562           0 :   (with-tramp-progress-reporter
     563           0 :       (tramp-dissect-file-name
     564           0 :        (if (tramp-tramp-file-p filename) filename newname))
     565           0 :       0 (format "Copying %s to %s" filename newname)
     566             : 
     567           0 :     (if (file-directory-p filename)
     568           0 :         (copy-directory
     569           0 :          filename newname keep-date 'parents 'copy-contents)
     570             : 
     571           0 :       (let ((tmpfile (file-local-copy filename)))
     572           0 :         (if tmpfile
     573             :             ;; Remote filename.
     574           0 :             (condition-case err
     575           0 :                 (rename-file tmpfile newname ok-if-already-exists)
     576             :               ((error quit)
     577           0 :                (delete-file tmpfile)
     578           0 :                (signal (car err) (cdr err))))
     579             : 
     580             :           ;; Remote newname.
     581           0 :           (when (file-directory-p newname)
     582           0 :             (setq newname
     583           0 :                   (expand-file-name (file-name-nondirectory filename) newname)))
     584             : 
     585           0 :           (with-parsed-tramp-file-name newname nil
     586           0 :             (when (and (not ok-if-already-exists)
     587           0 :                        (file-exists-p newname))
     588           0 :               (tramp-error v 'file-already-exists newname))
     589             : 
     590             :             ;; We must also flush the cache of the directory, because
     591             :             ;; `file-attributes' reads the values from there.
     592           0 :             (tramp-flush-file-property v (file-name-directory localname))
     593           0 :             (tramp-flush-file-property v localname)
     594           0 :             (unless (tramp-smb-get-share v)
     595           0 :               (tramp-error
     596           0 :                v 'file-error "Target `%s' must contain a share name" newname))
     597           0 :             (unless (tramp-smb-send-command
     598           0 :                      v (format "put \"%s\" \"%s\""
     599           0 :                                (tramp-compat-file-name-unquote filename)
     600           0 :                                (tramp-smb-get-localname v)))
     601           0 :               (tramp-error
     602           0 :                v 'file-error "Cannot copy `%s' to `%s'" filename newname))))))
     603             : 
     604             :     ;; KEEP-DATE handling.
     605           0 :     (when keep-date
     606           0 :       (set-file-times
     607           0 :        newname
     608           0 :        (tramp-compat-file-attribute-modification-time
     609           0 :         (file-attributes filename))))))
     610             : 
     611             : (defun tramp-smb-handle-delete-directory (directory &optional recursive _trash)
     612             :   "Like `delete-directory' for Tramp files."
     613           0 :   (setq directory (directory-file-name (expand-file-name directory)))
     614           0 :   (when (file-exists-p directory)
     615           0 :     (when recursive
     616           0 :       (mapc
     617             :        (lambda (file)
     618           0 :          (if (file-directory-p file)
     619           0 :              (delete-directory file recursive)
     620           0 :            (delete-file file)))
     621             :        ;; We do not want to delete "." and "..".
     622           0 :        (directory-files directory 'full directory-files-no-dot-files-regexp)))
     623             : 
     624           0 :     (with-parsed-tramp-file-name directory nil
     625             :       ;; We must also flush the cache of the directory, because
     626             :       ;; `file-attributes' reads the values from there.
     627           0 :       (tramp-flush-file-property v (file-name-directory localname))
     628           0 :       (tramp-flush-directory-property v localname)
     629           0 :       (unless (tramp-smb-send-command
     630           0 :                v (format
     631             :                   "%s \"%s\""
     632           0 :                   (if (tramp-smb-get-cifs-capabilities v) "posix_rmdir" "rmdir")
     633           0 :                   (tramp-smb-get-localname v)))
     634             :         ;; Error.
     635           0 :         (with-current-buffer (tramp-get-connection-buffer v)
     636           0 :           (goto-char (point-min))
     637           0 :           (search-forward-regexp tramp-smb-errors nil t)
     638           0 :           (tramp-error
     639           0 :            v 'file-error "%s `%s'" (match-string 0) directory))))))
     640             : 
     641             : (defun tramp-smb-handle-delete-file (filename &optional _trash)
     642             :   "Like `delete-file' for Tramp files."
     643           0 :   (setq filename (expand-file-name filename))
     644           0 :   (when (file-exists-p filename)
     645           0 :     (with-parsed-tramp-file-name filename nil
     646             :       ;; We must also flush the cache of the directory, because
     647             :       ;; `file-attributes' reads the values from there.
     648           0 :       (tramp-flush-file-property v (file-name-directory localname))
     649           0 :       (tramp-flush-file-property v localname)
     650           0 :       (unless (tramp-smb-send-command
     651           0 :                v (format
     652             :                   "%s \"%s\""
     653           0 :                   (if (tramp-smb-get-cifs-capabilities v) "posix_unlink" "rm")
     654           0 :                   (tramp-smb-get-localname v)))
     655             :         ;; Error.
     656           0 :         (with-current-buffer (tramp-get-connection-buffer v)
     657           0 :           (goto-char (point-min))
     658           0 :           (search-forward-regexp tramp-smb-errors nil t)
     659           0 :           (tramp-error
     660           0 :            v 'file-error "%s `%s'" (match-string 0) filename))))))
     661             : 
     662             : (defun tramp-smb-handle-directory-files
     663             :   (directory &optional full match nosort)
     664             :   "Like `directory-files' for Tramp files."
     665           0 :   (let ((result (mapcar 'directory-file-name
     666           0 :                         (file-name-all-completions "" directory))))
     667             :     ;; Discriminate with regexp.
     668           0 :     (when match
     669           0 :       (setq result
     670           0 :             (delete nil
     671           0 :                     (mapcar (lambda (x) (when (string-match match x) x))
     672           0 :                             result))))
     673             :     ;; Append directory.
     674           0 :     (when full
     675           0 :       (setq result
     676           0 :             (mapcar
     677           0 :              (lambda (x) (format "%s/%s" directory x))
     678           0 :              result)))
     679             :     ;; Sort them if necessary.
     680           0 :     (unless nosort (setq result (sort result 'string-lessp)))
     681           0 :     result))
     682             : 
     683             : (defun tramp-smb-handle-expand-file-name (name &optional dir)
     684             :   "Like `expand-file-name' for Tramp files."
     685             :   ;; If DIR is not given, use DEFAULT-DIRECTORY or "/".
     686           0 :   (setq dir (or dir default-directory "/"))
     687             :   ;; Unless NAME is absolute, concat DIR and NAME.
     688           0 :   (unless (file-name-absolute-p name)
     689           0 :     (setq name (concat (file-name-as-directory dir) name)))
     690             :   ;; If NAME is not a Tramp file, run the real handler.
     691           0 :   (if (not (tramp-tramp-file-p name))
     692           0 :       (tramp-run-real-handler 'expand-file-name (list name nil))
     693             :     ;; Dissect NAME.
     694           0 :     (with-parsed-tramp-file-name name nil
     695             :       ;; Tilde expansion if necessary.  We use the user name as share,
     696             :       ;; which is often the case in domains.
     697           0 :       (when (string-match "\\`/?~\\([^/]*\\)" localname)
     698           0 :         (setq localname
     699           0 :               (replace-match
     700           0 :                (if (zerop (length (match-string 1 localname)))
     701           0 :                    user
     702           0 :                  (match-string 1 localname))
     703           0 :                nil nil localname)))
     704             :       ;; Make the file name absolute.
     705           0 :       (unless (tramp-run-real-handler 'file-name-absolute-p (list localname))
     706           0 :         (setq localname (concat "/" localname)))
     707             :       ;; No tilde characters in file name, do normal
     708             :       ;; `expand-file-name' (this does "/./" and "/../").
     709           0 :       (tramp-make-tramp-file-name
     710           0 :        method user domain host port
     711           0 :        (tramp-run-real-handler 'expand-file-name (list localname))))))
     712             : 
     713             : (defun tramp-smb-action-get-acl (proc vec)
     714             :   "Read ACL data from connection buffer."
     715           0 :   (unless (process-live-p proc)
     716             :     ;; Accept pending output.
     717           0 :     (while (tramp-accept-process-output proc 0.1))
     718           0 :     (with-current-buffer (tramp-get-connection-buffer vec)
     719             :       ;; There might be a hidden password prompt.
     720           0 :       (widen)
     721           0 :       (tramp-message vec 10 "\n%s" (buffer-string))
     722           0 :       (goto-char (point-min))
     723           0 :       (while (and (not (eobp)) (not (looking-at "^REVISION:")))
     724           0 :         (forward-line)
     725           0 :         (delete-region (point-min) (point)))
     726           0 :       (while (and (not (eobp)) (looking-at "^.+:.+"))
     727           0 :         (forward-line))
     728           0 :       (delete-region (point) (point-max))
     729           0 :       (throw 'tramp-action 'ok))))
     730             : 
     731             : (defun tramp-smb-handle-file-acl (filename)
     732             :   "Like `file-acl' for Tramp files."
     733           0 :   (with-parsed-tramp-file-name filename nil
     734           0 :     (with-tramp-file-property v localname "file-acl"
     735           0 :       (when (executable-find tramp-smb-acl-program)
     736             :         ;; Set variables for computing the prompt for reading password.
     737           0 :         (setq tramp-current-method method
     738           0 :               tramp-current-user user
     739           0 :               tramp-current-domain domain
     740           0 :               tramp-current-host host
     741           0 :               tramp-current-port port)
     742             : 
     743           0 :         (let* ((share     (tramp-smb-get-share v))
     744           0 :                (localname (replace-regexp-in-string
     745           0 :                            "\\\\" "/" (tramp-smb-get-localname v)))
     746           0 :                (args      (list (concat "//" host "/" share) "-E")))
     747             : 
     748           0 :           (if (not (zerop (length user)))
     749           0 :               (setq args (append args (list "-U" user)))
     750           0 :             (setq args (append args (list "-N"))))
     751             : 
     752           0 :           (when domain (setq args (append args (list "-W" domain))))
     753           0 :           (when port   (setq args (append args (list "-p" port))))
     754           0 :           (when tramp-smb-conf
     755           0 :             (setq args (append args (list "-s" tramp-smb-conf))))
     756           0 :           (setq
     757             :            args
     758           0 :            (append args (list (tramp-unquote-shell-quote-argument localname)
     759           0 :                               "2>/dev/null")))
     760             : 
     761           0 :           (unwind-protect
     762           0 :               (with-temp-buffer
     763             :                 ;; Set the transfer process properties.
     764           0 :                 (tramp-set-connection-property
     765           0 :                  v "process-name" (buffer-name (current-buffer)))
     766           0 :                 (tramp-set-connection-property
     767           0 :                  v "process-buffer" (current-buffer))
     768             : 
     769             :                 ;; Use an asynchronous processes.  By this, password
     770             :                 ;; can be handled.
     771           0 :                 (let ((p (apply
     772             :                           'start-process
     773           0 :                           (tramp-get-connection-name v)
     774           0 :                           (tramp-get-connection-buffer v)
     775           0 :                           tramp-smb-acl-program args)))
     776             : 
     777           0 :                   (tramp-message
     778           0 :                    v 6 "%s" (mapconcat 'identity (process-command p) " "))
     779           0 :                   (tramp-set-connection-property p "vector" v)
     780           0 :                   (process-put p 'adjust-window-size-function 'ignore)
     781           0 :                   (set-process-query-on-exit-flag p nil)
     782           0 :                   (tramp-process-actions p v nil tramp-smb-actions-get-acl)
     783           0 :                   (when (> (point-max) (point-min))
     784           0 :                     (substring-no-properties (buffer-string)))))
     785             : 
     786             :             ;; Reset the transfer process properties.
     787           0 :             (tramp-set-connection-property v "process-name" nil)
     788           0 :             (tramp-set-connection-property v "process-buffer" nil)))))))
     789             : 
     790             : (defun tramp-smb-handle-file-attributes (filename &optional id-format)
     791             :   "Like `file-attributes' for Tramp files."
     792           0 :   (unless id-format (setq id-format 'integer))
     793           0 :   (ignore-errors
     794           0 :     (with-parsed-tramp-file-name filename nil
     795           0 :       (with-tramp-file-property
     796           0 :           v localname (format "file-attributes-%s" id-format)
     797           0 :         (if (tramp-smb-get-stat-capability v)
     798           0 :             (tramp-smb-do-file-attributes-with-stat v id-format)
     799             :           ;; Reading just the filename entry via "dir localname" is not
     800             :           ;; possible, because when filename is a directory, some
     801             :           ;; smbclient versions return the content of the directory, and
     802             :           ;; other versions don't.  Therefore, the whole content of the
     803             :           ;; upper directory is retrieved, and the entry of the filename
     804             :           ;; is extracted from.
     805           0 :           (let* ((entries (tramp-smb-get-file-entries
     806           0 :                            (file-name-directory filename)))
     807           0 :                  (entry (assoc (file-name-nondirectory filename) entries))
     808           0 :                  (uid (if (equal id-format 'string) "nobody" -1))
     809           0 :                  (gid (if (equal id-format 'string) "nogroup" -1))
     810           0 :                  (inode (tramp-get-inode v))
     811           0 :                  (device (tramp-get-device v)))
     812             : 
     813             :             ;; Check result.
     814           0 :             (when entry
     815           0 :               (list (and (string-match "d" (nth 1 entry))
     816           0 :                          t)        ;0 file type
     817             :                     -1             ;1 link count
     818           0 :                     uid            ;2 uid
     819           0 :                     gid            ;3 gid
     820             :                     '(0 0)         ;4 atime
     821           0 :                     (nth 3 entry)  ;5 mtime
     822             :                     '(0 0)         ;6 ctime
     823           0 :                     (nth 2 entry)  ;7 size
     824           0 :                     (nth 1 entry)  ;8 mode
     825             :                     nil            ;9 gid weird
     826           0 :                     inode          ;10 inode number
     827           0 :                     device)))))))) ;11 file system number
     828             : 
     829             : (defun tramp-smb-do-file-attributes-with-stat (vec &optional id-format)
     830             :   "Implement `file-attributes' for Tramp files using stat command."
     831           0 :   (tramp-message
     832           0 :    vec 5 "file attributes with stat: %s" (tramp-file-name-localname vec))
     833           0 :   (with-current-buffer (tramp-get-connection-buffer vec)
     834           0 :     (let* (size id link uid gid atime mtime ctime mode inode)
     835           0 :       (when (tramp-smb-send-command
     836           0 :              vec (format "stat \"%s\"" (tramp-smb-get-localname vec)))
     837             : 
     838             :         ;; Loop the listing.
     839           0 :         (goto-char (point-min))
     840           0 :         (unless (re-search-forward tramp-smb-errors nil t)
     841           0 :           (while (not (eobp))
     842           0 :             (cond
     843           0 :              ((looking-at
     844           0 :                "Size:\\s-+\\([0-9]+\\)\\s-+Blocks:\\s-+[0-9]+\\s-+\\(\\w+\\)")
     845           0 :               (setq size (string-to-number (match-string 1))
     846           0 :                     id (if (string-equal "directory" (match-string 2)) t
     847           0 :                          (if (string-equal "symbolic" (match-string 2)) ""))))
     848           0 :              ((looking-at
     849           0 :                "Inode:\\s-+\\([0-9]+\\)\\s-+Links:\\s-+\\([0-9]+\\)")
     850           0 :               (setq inode (string-to-number (match-string 1))
     851           0 :                     link (string-to-number (match-string 2))))
     852           0 :              ((looking-at
     853           0 :                "Access:\\s-+([0-9]+/\\(\\S-+\\))\\s-+Uid:\\s-+\\([0-9]+\\)\\s-+Gid:\\s-+\\([0-9]+\\)")
     854           0 :               (setq mode (match-string 1)
     855           0 :                     uid (if (equal id-format 'string) (match-string 2)
     856           0 :                           (string-to-number (match-string 2)))
     857           0 :                     gid (if (equal id-format 'string) (match-string 3)
     858           0 :                           (string-to-number (match-string 3)))))
     859           0 :              ((looking-at
     860           0 :                "Access:\\s-+\\([0-9]+\\)-\\([0-9]+\\)-\\([0-9]+\\)\\s-+\\([0-9]+\\):\\([0-9]+\\):\\([0-9]+\\)")
     861           0 :               (setq atime
     862           0 :                     (encode-time
     863           0 :                      (string-to-number (match-string 6)) ;; sec
     864           0 :                      (string-to-number (match-string 5)) ;; min
     865           0 :                      (string-to-number (match-string 4)) ;; hour
     866           0 :                      (string-to-number (match-string 3)) ;; day
     867           0 :                      (string-to-number (match-string 2)) ;; month
     868           0 :                      (string-to-number (match-string 1))))) ;; year
     869           0 :              ((looking-at
     870           0 :                "Modify:\\s-+\\([0-9]+\\)-\\([0-9]+\\)-\\([0-9]+\\)\\s-+\\([0-9]+\\):\\([0-9]+\\):\\([0-9]+\\)")
     871           0 :               (setq mtime
     872           0 :                     (encode-time
     873           0 :                      (string-to-number (match-string 6)) ;; sec
     874           0 :                      (string-to-number (match-string 5)) ;; min
     875           0 :                      (string-to-number (match-string 4)) ;; hour
     876           0 :                      (string-to-number (match-string 3)) ;; day
     877           0 :                      (string-to-number (match-string 2)) ;; month
     878           0 :                      (string-to-number (match-string 1))))) ;; year
     879           0 :              ((looking-at
     880           0 :                "Change:\\s-+\\([0-9]+\\)-\\([0-9]+\\)-\\([0-9]+\\)\\s-+\\([0-9]+\\):\\([0-9]+\\):\\([0-9]+\\)")
     881           0 :               (setq ctime
     882           0 :                     (encode-time
     883           0 :                      (string-to-number (match-string 6)) ;; sec
     884           0 :                      (string-to-number (match-string 5)) ;; min
     885           0 :                      (string-to-number (match-string 4)) ;; hour
     886           0 :                      (string-to-number (match-string 3)) ;; day
     887           0 :                      (string-to-number (match-string 2)) ;; month
     888           0 :                      (string-to-number (match-string 1)))))) ;; year
     889           0 :             (forward-line))
     890             :           ;; Return the result.
     891           0 :           (list id link uid gid atime mtime ctime size mode nil inode
     892           0 :                 (tramp-get-device vec)))))))
     893             : 
     894             : (defun tramp-smb-handle-file-directory-p (filename)
     895             :   "Like `file-directory-p' for Tramp files."
     896           0 :   (and (file-exists-p filename)
     897           0 :        (eq ?d
     898           0 :            (aref (tramp-compat-file-attribute-modes (file-attributes filename))
     899           0 :                  0))))
     900             : 
     901             : (defun tramp-smb-handle-file-local-copy (filename)
     902             :   "Like `file-local-copy' for Tramp files."
     903           0 :   (with-parsed-tramp-file-name filename nil
     904           0 :     (unless (file-exists-p filename)
     905           0 :       (tramp-error
     906           0 :        v tramp-file-missing
     907           0 :        "Cannot make local copy of non-existing file `%s'" filename))
     908           0 :     (let ((tmpfile (tramp-compat-make-temp-file filename)))
     909           0 :       (with-tramp-progress-reporter
     910           0 :           v 3 (format "Fetching %s to tmp file %s" filename tmpfile)
     911           0 :         (unless (tramp-smb-send-command
     912           0 :                  v (format "get \"%s\" \"%s\""
     913           0 :                            (tramp-smb-get-localname v) tmpfile))
     914             :           ;; Oops, an error.  We shall cleanup.
     915           0 :           (delete-file tmpfile)
     916           0 :           (tramp-error
     917           0 :            v 'file-error "Cannot make local copy of file `%s'" filename)))
     918           0 :       tmpfile)))
     919             : 
     920             : ;; This function should return "foo/" for directories and "bar" for
     921             : ;; files.
     922             : (defun tramp-smb-handle-file-name-all-completions (filename directory)
     923             :   "Like `file-name-all-completions' for Tramp files."
     924           0 :   (all-completions
     925           0 :    filename
     926           0 :    (with-parsed-tramp-file-name (expand-file-name directory) nil
     927           0 :      (with-tramp-file-property v localname "file-name-all-completions"
     928           0 :        (save-match-data
     929           0 :          (delete-dups
     930           0 :           (mapcar
     931             :            (lambda (x)
     932           0 :              (list
     933           0 :               (if (string-match "d" (nth 1 x))
     934           0 :                   (file-name-as-directory (nth 0 x))
     935           0 :                 (nth 0 x))))
     936           0 :            (tramp-smb-get-file-entries directory))))))))
     937             : 
     938             : (defun tramp-smb-handle-file-writable-p (filename)
     939             :   "Like `file-writable-p' for Tramp files."
     940           0 :   (if (file-exists-p filename)
     941           0 :       (string-match
     942             :        "w"
     943           0 :        (or (tramp-compat-file-attribute-modes (file-attributes filename)) ""))
     944           0 :     (let ((dir (file-name-directory filename)))
     945           0 :       (and (file-exists-p dir)
     946           0 :            (file-writable-p dir)))))
     947             : 
     948             : (defun tramp-smb-handle-insert-directory
     949             :   (filename switches &optional wildcard full-directory-p)
     950             :   "Like `insert-directory' for Tramp files."
     951           0 :   (setq filename (expand-file-name filename))
     952           0 :   (unless switches (setq switches ""))
     953             :   ;; Mark trailing "/".
     954           0 :   (when (and (zerop (length (file-name-nondirectory filename)))
     955           0 :              (not full-directory-p))
     956           0 :     (setq switches (concat switches "F")))
     957           0 :   (if full-directory-p
     958             :       ;; Called from `dired-add-entry'.
     959           0 :       (setq filename (file-name-as-directory filename))
     960           0 :     (setq filename (directory-file-name filename)))
     961           0 :   (with-parsed-tramp-file-name filename nil
     962           0 :     (with-tramp-progress-reporter v 0 (format "Opening directory %s" filename)
     963           0 :       (save-match-data
     964           0 :         (let ((base (file-name-nondirectory filename))
     965             :               ;; We should not destroy the cache entry.
     966           0 :               (entries (copy-sequence
     967           0 :                         (tramp-smb-get-file-entries
     968           0 :                          (file-name-directory filename)))))
     969             : 
     970           0 :           (when wildcard
     971           0 :             (string-match "\\." base)
     972           0 :             (setq base (replace-match "\\\\." nil nil base))
     973           0 :             (string-match "\\*" base)
     974           0 :             (setq base (replace-match ".*" nil nil base))
     975           0 :             (string-match "\\?" base)
     976           0 :             (setq base (replace-match ".?" nil nil base)))
     977             : 
     978             :           ;; Filter entries.
     979           0 :           (setq entries
     980           0 :                 (delq
     981             :                  nil
     982           0 :                  (if (or wildcard (zerop (length base)))
     983             :                      ;; Check for matching entries.
     984           0 :                      (mapcar
     985             :                       (lambda (x)
     986           0 :                         (when (string-match
     987           0 :                                (format "^%s" base) (nth 0 x))
     988           0 :                           x))
     989           0 :                       entries)
     990             :                    ;; We just need the only and only entry FILENAME.
     991           0 :                    (list (assoc base entries)))))
     992             : 
     993             :           ;; Sort entries.
     994           0 :           (setq entries
     995           0 :                 (sort
     996           0 :                  entries
     997             :                  (lambda (x y)
     998           0 :                    (if (string-match "t" switches)
     999             :                        ;; Sort by date.
    1000           0 :                        (time-less-p (nth 3 y) (nth 3 x))
    1001             :                      ;; Sort by name.
    1002           0 :                      (string-lessp (nth 0 x) (nth 0 y))))))
    1003             : 
    1004             :           ;; Handle "-F" switch.
    1005           0 :           (when (string-match "F" switches)
    1006           0 :             (mapc
    1007             :              (lambda (x)
    1008           0 :                (when (not (zerop (length (car x))))
    1009           0 :                  (cond
    1010           0 :                   ((char-equal ?d (string-to-char (nth 1 x)))
    1011           0 :                    (setcar x (concat (car x) "/")))
    1012           0 :                   ((char-equal ?x (string-to-char (nth 1 x)))
    1013           0 :                    (setcar x (concat (car x) "*"))))))
    1014           0 :              entries))
    1015             : 
    1016             :           ;; Print entries.
    1017           0 :           (mapc
    1018             :            (lambda (x)
    1019           0 :              (when (not (zerop (length (nth 0 x))))
    1020           0 :                (when (string-match "l" switches)
    1021           0 :                  (let ((attr
    1022           0 :                         (when (tramp-smb-get-stat-capability v)
    1023           0 :                           (ignore-errors
    1024           0 :                             (file-attributes filename 'string)))))
    1025           0 :                    (insert
    1026           0 :                     (format
    1027             :                      "%10s %3d %-8s %-8s %8s %s "
    1028           0 :                      (or (tramp-compat-file-attribute-modes attr) (nth 1 x))
    1029           0 :                      (or (tramp-compat-file-attribute-link-number attr) 1)
    1030           0 :                      (or (tramp-compat-file-attribute-user-id attr) "nobody")
    1031           0 :                      (or (tramp-compat-file-attribute-group-id attr) "nogroup")
    1032           0 :                      (or (tramp-compat-file-attribute-size attr) (nth 2 x))
    1033           0 :                      (format-time-string
    1034           0 :                       (if (time-less-p (time-subtract (current-time) (nth 3 x))
    1035           0 :                            tramp-half-a-year)
    1036             :                           "%b %e %R"
    1037           0 :                         "%b %e  %Y")
    1038           0 :                       (nth 3 x)))))) ; date
    1039             : 
    1040             :                ;; We mark the file name.  The inserted name could be
    1041             :                ;; from somewhere else, so we use the relative file name
    1042             :                ;; of `default-directory'.
    1043           0 :                (let ((start (point)))
    1044           0 :                  (insert
    1045           0 :                   (format
    1046             :                    "%s\n"
    1047           0 :                    (file-relative-name
    1048           0 :                     (expand-file-name
    1049           0 :                      (nth 0 x) (file-name-directory filename))
    1050           0 :                     (when full-directory-p (file-name-directory filename)))))
    1051           0 :                  (put-text-property start (1- (point)) 'dired-filename t))
    1052           0 :                (forward-line)
    1053           0 :                (beginning-of-line)))
    1054           0 :            entries))))))
    1055             : 
    1056             : (defun tramp-smb-handle-make-directory (dir &optional parents)
    1057             :   "Like `make-directory' for Tramp files."
    1058           0 :   (setq dir (directory-file-name (expand-file-name dir)))
    1059           0 :   (unless (file-name-absolute-p dir)
    1060           0 :     (setq dir (expand-file-name dir default-directory)))
    1061           0 :   (with-parsed-tramp-file-name dir nil
    1062           0 :     (save-match-data
    1063           0 :       (let* ((ldir (file-name-directory dir)))
    1064             :         ;; Make missing directory parts.
    1065           0 :         (when (and parents
    1066           0 :                    (tramp-smb-get-share v)
    1067           0 :                    (not (file-directory-p ldir)))
    1068           0 :           (make-directory ldir parents))
    1069             :         ;; Just do it.
    1070           0 :         (when (file-directory-p ldir)
    1071           0 :           (make-directory-internal dir))
    1072           0 :         (unless (file-directory-p dir)
    1073           0 :           (tramp-error v 'file-error "Couldn't make directory %s" dir))))))
    1074             : 
    1075             : (defun tramp-smb-handle-make-directory-internal (directory)
    1076             :   "Like `make-directory-internal' for Tramp files."
    1077           0 :   (setq directory (directory-file-name (expand-file-name directory)))
    1078           0 :   (unless (file-name-absolute-p directory)
    1079           0 :     (setq directory (expand-file-name directory default-directory)))
    1080           0 :   (with-parsed-tramp-file-name directory nil
    1081           0 :     (save-match-data
    1082           0 :       (let* ((file (tramp-smb-get-localname v)))
    1083           0 :         (when (file-directory-p (file-name-directory directory))
    1084           0 :           (tramp-smb-send-command
    1085           0 :            v
    1086           0 :            (if (tramp-smb-get-cifs-capabilities v)
    1087           0 :                (format "posix_mkdir \"%s\" %o" file (default-file-modes))
    1088           0 :              (format "mkdir \"%s\"" file)))
    1089             :           ;; We must also flush the cache of the directory, because
    1090             :           ;; `file-attributes' reads the values from there.
    1091           0 :           (tramp-flush-file-property v (file-name-directory localname))
    1092           0 :           (tramp-flush-file-property v localname))
    1093           0 :         (unless (file-directory-p directory)
    1094           0 :           (tramp-error
    1095           0 :            v 'file-error "Couldn't make directory %s" directory))))))
    1096             : 
    1097             : (defun tramp-smb-handle-make-symbolic-link
    1098             :   (filename linkname &optional ok-if-already-exists)
    1099             :   "Like `make-symbolic-link' for Tramp files.
    1100             : If LINKNAME is a non-Tramp file, it is used verbatim as the target of
    1101             : the symlink.  If LINKNAME is a Tramp file, only the localname component is
    1102             : used as the target of the symlink.
    1103             : 
    1104             : If LINKNAME is a Tramp file and the localname component is relative, then
    1105             : it is expanded first, before the localname component is taken.  Note that
    1106             : this can give surprising results if the user/host for the source and
    1107             : target of the symlink differ."
    1108           0 :   (unless (tramp-equal-remote filename linkname)
    1109           0 :     (with-parsed-tramp-file-name
    1110           0 :         (if (tramp-tramp-file-p filename) filename linkname) nil
    1111           0 :       (tramp-error
    1112           0 :        v 'file-error
    1113             :        "make-symbolic-link: %s"
    1114           0 :        "only implemented for same method, same user, same host")))
    1115           0 :   (with-parsed-tramp-file-name filename v1
    1116           0 :     (with-parsed-tramp-file-name linkname v2
    1117           0 :       (when (file-directory-p filename)
    1118           0 :         (tramp-error
    1119           0 :          v2 'file-error
    1120           0 :          "make-symbolic-link: %s must not be a directory" filename))
    1121           0 :       (when (and (not ok-if-already-exists)
    1122           0 :                  (file-exists-p linkname)
    1123           0 :                  (not (numberp ok-if-already-exists))
    1124           0 :                  (y-or-n-p
    1125           0 :                   (format
    1126             :                    "File %s already exists; make it a new name anyway? "
    1127           0 :                    linkname)))
    1128           0 :         (tramp-error v2 'file-already-exists linkname))
    1129           0 :       (unless (tramp-smb-get-cifs-capabilities v1)
    1130           0 :         (tramp-error v2 'file-error "make-symbolic-link not supported"))
    1131             :       ;; We must also flush the cache of the directory, because
    1132             :       ;; `file-attributes' reads the values from there.
    1133           0 :       (tramp-flush-file-property v2 (file-name-directory v2-localname))
    1134           0 :       (tramp-flush-file-property v2 v2-localname)
    1135           0 :       (unless
    1136           0 :           (tramp-smb-send-command
    1137           0 :            v1
    1138           0 :            (format
    1139             :             "symlink \"%s\" \"%s\""
    1140           0 :             (tramp-smb-get-localname v1)
    1141           0 :             (tramp-smb-get-localname v2)))
    1142           0 :         (tramp-error
    1143           0 :          v2 'file-error
    1144             :          "error with make-symbolic-link, see buffer `%s' for details"
    1145           0 :          (buffer-name))))))
    1146             : 
    1147             : (defun tramp-smb-handle-process-file
    1148             :   (program &optional infile destination display &rest args)
    1149             :   "Like `process-file' for Tramp files."
    1150             :   ;; The implementation is not complete yet.
    1151           0 :   (when (and (numberp destination) (zerop destination))
    1152           0 :     (error "Implementation does not handle immediate return"))
    1153             : 
    1154           0 :   (with-parsed-tramp-file-name default-directory nil
    1155           0 :     (let* ((name (file-name-nondirectory program))
    1156           0 :            (name1 name)
    1157             :            (i 0)
    1158             :            input tmpinput outbuf command ret)
    1159             : 
    1160             :       ;; Determine input.
    1161           0 :       (when infile
    1162           0 :         (setq infile (expand-file-name infile))
    1163           0 :         (if (tramp-equal-remote default-directory infile)
    1164             :             ;; INFILE is on the same remote host.
    1165           0 :             (setq input (with-parsed-tramp-file-name infile nil localname))
    1166             :           ;; INFILE must be copied to remote host.
    1167           0 :           (setq input (tramp-make-tramp-temp-file v)
    1168             :                 tmpinput
    1169           0 :                 (tramp-make-tramp-file-name method user domain host port input))
    1170           0 :           (copy-file infile tmpinput t))
    1171             :         ;; Transform input into a filename powershell does understand.
    1172           0 :         (setq input (format "//%s%s" host input)))
    1173             : 
    1174             :       ;; Determine output.
    1175           0 :       (cond
    1176             :        ;; Just a buffer.
    1177           0 :        ((bufferp destination)
    1178           0 :         (setq outbuf destination))
    1179             :        ;; A buffer name.
    1180           0 :        ((stringp destination)
    1181           0 :         (setq outbuf (get-buffer-create destination)))
    1182             :        ;; (REAL-DESTINATION ERROR-DESTINATION)
    1183           0 :        ((consp destination)
    1184             :         ;; output.
    1185           0 :         (cond
    1186           0 :          ((bufferp (car destination))
    1187           0 :           (setq outbuf (car destination)))
    1188           0 :          ((stringp (car destination))
    1189           0 :           (setq outbuf (get-buffer-create (car destination))))
    1190           0 :          ((car destination)
    1191           0 :           (setq outbuf (current-buffer))))
    1192             :         ;; stderr.
    1193           0 :         (tramp-message v 2 "%s" "STDERR not supported"))
    1194             :        ;; 't
    1195           0 :        (destination
    1196           0 :         (setq outbuf (current-buffer))))
    1197             : 
    1198             :       ;; Construct command.
    1199           0 :       (setq command (mapconcat 'identity (cons program args) " ")
    1200           0 :             command (if input
    1201           0 :                         (format
    1202             :                          "get-content %s | & %s"
    1203           0 :                          (tramp-smb-shell-quote-argument input) command)
    1204           0 :                       (format "& %s" command)))
    1205             : 
    1206           0 :       (while (get-process name1)
    1207             :         ;; NAME must be unique as process name.
    1208           0 :         (setq i (1+ i)
    1209           0 :               name1 (format "%s<%d>" name i)))
    1210             : 
    1211             :       ;; Set the new process properties.
    1212           0 :       (tramp-set-connection-property v "process-name" name1)
    1213           0 :       (tramp-set-connection-property
    1214           0 :        v "process-buffer"
    1215           0 :        (or outbuf (generate-new-buffer tramp-temp-buffer-name)))
    1216             : 
    1217             :       ;; Call it.
    1218           0 :       (condition-case nil
    1219           0 :           (with-current-buffer (tramp-get-connection-buffer v)
    1220             :             ;; Preserve buffer contents.
    1221           0 :             (narrow-to-region (point-max) (point-max))
    1222           0 :             (tramp-smb-call-winexe v)
    1223           0 :             (when (tramp-smb-get-share v)
    1224           0 :               (tramp-smb-send-command
    1225           0 :                v (format "cd \"//%s%s\"" host (file-name-directory localname))))
    1226           0 :             (tramp-smb-send-command v command)
    1227             :             ;; Preserve command output.
    1228           0 :             (narrow-to-region (point-max) (point-max))
    1229           0 :             (let ((p (tramp-get-connection-process v)))
    1230           0 :               (tramp-smb-send-command v "exit $lasterrorcode")
    1231           0 :               (while (process-live-p p)
    1232           0 :                 (sleep-for 0.1)
    1233           0 :                 (setq ret (process-exit-status p))))
    1234           0 :             (delete-region (point-min) (point-max))
    1235           0 :             (widen))
    1236             : 
    1237             :         ;; When the user did interrupt, we should do it also.  We use
    1238             :         ;; return code -1 as marker.
    1239             :         (quit
    1240           0 :          (setq ret -1))
    1241             :         ;; Handle errors.
    1242             :         (error
    1243           0 :          (setq ret 1)))
    1244             : 
    1245             :       ;; We should redisplay the output.
    1246           0 :       (when (and display outbuf (get-buffer-window outbuf t)) (redisplay))
    1247             : 
    1248             :       ;; Cleanup.  We remove all file cache values for the connection,
    1249             :       ;; because the remote process could have changed them.
    1250           0 :       (tramp-set-connection-property v "process-name" nil)
    1251           0 :       (tramp-set-connection-property v "process-buffer" nil)
    1252           0 :       (when tmpinput (delete-file tmpinput))
    1253           0 :       (unless outbuf
    1254           0 :         (kill-buffer (tramp-get-connection-property v "process-buffer" nil)))
    1255             : 
    1256           0 :       (unless process-file-side-effects
    1257           0 :         (tramp-flush-directory-property v ""))
    1258             : 
    1259             :       ;; Return exit status.
    1260           0 :       (if (equal ret -1)
    1261           0 :           (keyboard-quit)
    1262           0 :         ret))))
    1263             : 
    1264             : (defun tramp-smb-handle-rename-file
    1265             :   (filename newname &optional ok-if-already-exists)
    1266             :   "Like `rename-file' for Tramp files."
    1267           0 :   (setq filename (expand-file-name filename)
    1268           0 :         newname (expand-file-name newname))
    1269             : 
    1270           0 :   (when (and (not ok-if-already-exists)
    1271           0 :              (file-exists-p newname))
    1272           0 :     (tramp-error
    1273           0 :      (tramp-dissect-file-name
    1274           0 :       (if (tramp-tramp-file-p filename) filename newname))
    1275           0 :      'file-already-exists newname))
    1276             : 
    1277           0 :   (with-tramp-progress-reporter
    1278           0 :       (tramp-dissect-file-name
    1279           0 :        (if (tramp-tramp-file-p filename) filename newname))
    1280           0 :       0 (format "Renaming %s to %s" filename newname)
    1281             : 
    1282           0 :     (if (and (not (file-exists-p newname))
    1283           0 :              (tramp-equal-remote filename newname)
    1284           0 :              (string-equal
    1285           0 :               (tramp-smb-get-share (tramp-dissect-file-name filename))
    1286           0 :               (tramp-smb-get-share (tramp-dissect-file-name newname))))
    1287             :         ;; We can rename directly.
    1288           0 :         (with-parsed-tramp-file-name filename v1
    1289           0 :           (with-parsed-tramp-file-name newname v2
    1290             : 
    1291             :             ;; We must also flush the cache of the directory, because
    1292             :             ;; `file-attributes' reads the values from there.
    1293           0 :             (tramp-flush-file-property v1 (file-name-directory v1-localname))
    1294           0 :             (tramp-flush-file-property v1 v1-localname)
    1295           0 :             (tramp-flush-file-property v2 (file-name-directory v2-localname))
    1296           0 :             (tramp-flush-file-property v2 v2-localname)
    1297           0 :             (unless (tramp-smb-get-share v2)
    1298           0 :               (tramp-error
    1299           0 :                v2 'file-error "Target `%s' must contain a share name" newname))
    1300           0 :             (unless (tramp-smb-send-command
    1301           0 :                      v2 (format "rename \"%s\" \"%s\""
    1302           0 :                                 (tramp-smb-get-localname v1)
    1303           0 :                                 (tramp-smb-get-localname v2)))
    1304           0 :               (tramp-error v2 'file-error "Cannot rename `%s'" filename))))
    1305             : 
    1306             :       ;; We must rename via copy.
    1307           0 :       (copy-file
    1308           0 :        filename newname ok-if-already-exists 'keep-time 'preserve-uid-gid)
    1309           0 :       (if (file-directory-p filename)
    1310           0 :           (delete-directory filename 'recursive)
    1311           0 :         (delete-file filename)))))
    1312             : 
    1313             : (defun tramp-smb-action-set-acl (proc vec)
    1314             :   "Read ACL data from connection buffer."
    1315           0 :   (unless (process-live-p proc)
    1316             :     ;; Accept pending output.
    1317           0 :     (while (tramp-accept-process-output proc 0.1))
    1318           0 :     (with-current-buffer (tramp-get-connection-buffer vec)
    1319           0 :       (tramp-message vec 10 "\n%s" (buffer-string))
    1320           0 :       (throw 'tramp-action 'ok))))
    1321             : 
    1322             : (defun tramp-smb-handle-set-file-acl (filename acl-string)
    1323             :   "Like `set-file-acl' for Tramp files."
    1324           0 :   (ignore-errors
    1325           0 :     (with-parsed-tramp-file-name filename nil
    1326           0 :       (when (and (stringp acl-string) (executable-find tramp-smb-acl-program))
    1327             :         ;; Set variables for computing the prompt for reading password.
    1328           0 :         (setq tramp-current-method method
    1329           0 :               tramp-current-user user
    1330           0 :               tramp-current-domain domain
    1331           0 :               tramp-current-host host
    1332           0 :               tramp-current-port port)
    1333           0 :         (tramp-set-file-property v localname "file-acl" 'undef)
    1334             : 
    1335           0 :         (let* ((share     (tramp-smb-get-share v))
    1336           0 :                (localname (replace-regexp-in-string
    1337           0 :                            "\\\\" "/" (tramp-smb-get-localname v)))
    1338           0 :                (args      (list (concat "//" host "/" share) "-E" "-S"
    1339           0 :                                 (replace-regexp-in-string
    1340           0 :                                  "\n" "," acl-string))))
    1341             : 
    1342           0 :           (if (not (zerop (length user)))
    1343           0 :               (setq args (append args (list "-U" user)))
    1344           0 :             (setq args (append args (list "-N"))))
    1345             : 
    1346           0 :           (when domain (setq args (append args (list "-W" domain))))
    1347           0 :           (when port   (setq args (append args (list "-p" port))))
    1348           0 :           (when tramp-smb-conf
    1349           0 :             (setq args (append args (list "-s" tramp-smb-conf))))
    1350           0 :           (setq
    1351             :            args
    1352           0 :            (append args (list (tramp-unquote-shell-quote-argument localname)
    1353             :                               "&&" "echo" "tramp_exit_status" "0"
    1354           0 :                               "||" "echo" "tramp_exit_status" "1")))
    1355             : 
    1356           0 :           (unwind-protect
    1357           0 :               (with-temp-buffer
    1358             :                 ;; Set the transfer process properties.
    1359           0 :                 (tramp-set-connection-property
    1360           0 :                  v "process-name" (buffer-name (current-buffer)))
    1361           0 :                 (tramp-set-connection-property
    1362           0 :                  v "process-buffer" (current-buffer))
    1363             : 
    1364             :                 ;; Use an asynchronous processes.  By this, password can
    1365             :                 ;; be handled.
    1366           0 :                 (let ((p (apply
    1367             :                           'start-process
    1368           0 :                           (tramp-get-connection-name v)
    1369           0 :                           (tramp-get-connection-buffer v)
    1370           0 :                           tramp-smb-acl-program args)))
    1371             : 
    1372           0 :                   (tramp-message
    1373           0 :                    v 6 "%s" (mapconcat 'identity (process-command p) " "))
    1374           0 :                   (tramp-set-connection-property p "vector" v)
    1375           0 :                   (process-put p 'adjust-window-size-function 'ignore)
    1376           0 :                   (set-process-query-on-exit-flag p nil)
    1377           0 :                   (tramp-process-actions p v nil tramp-smb-actions-set-acl)
    1378           0 :                   (goto-char (point-max))
    1379           0 :                   (unless (re-search-backward "tramp_exit_status [0-9]+" nil t)
    1380           0 :                     (tramp-error
    1381           0 :                      v 'file-error
    1382           0 :                      "Couldn't find exit status of `%s'" tramp-smb-acl-program))
    1383           0 :                   (skip-chars-forward "^ ")
    1384           0 :                   (when (zerop (read (current-buffer)))
    1385             :                     ;; Success.
    1386           0 :                     (tramp-set-file-property v localname "file-acl" acl-string)
    1387           0 :                     t)))
    1388             : 
    1389             :             ;; Reset the transfer process properties.
    1390           0 :             (tramp-set-connection-property v "process-name" nil)
    1391           0 :             (tramp-set-connection-property v "process-buffer" nil)))))))
    1392             : 
    1393             : (defun tramp-smb-handle-set-file-modes (filename mode)
    1394             :   "Like `set-file-modes' for Tramp files."
    1395           0 :   (with-parsed-tramp-file-name filename nil
    1396           0 :     (when (tramp-smb-get-cifs-capabilities v)
    1397           0 :       (tramp-flush-file-property v localname)
    1398           0 :       (unless (tramp-smb-send-command
    1399           0 :                v (format "chmod \"%s\" %o" (tramp-smb-get-localname v) mode))
    1400           0 :         (tramp-error
    1401           0 :          v 'file-error "Error while changing file's mode %s" filename)))))
    1402             : 
    1403             : ;; We use BUFFER also as connection buffer during setup. Because of
    1404             : ;; this, its original contents must be saved, and restored once
    1405             : ;; connection has been setup.
    1406             : (defun tramp-smb-handle-start-file-process (name buffer program &rest args)
    1407             :   "Like `start-file-process' for Tramp files."
    1408           0 :   (with-parsed-tramp-file-name default-directory nil
    1409           0 :     (let* ((buffer
    1410           0 :             (if buffer
    1411           0 :                 (get-buffer-create buffer)
    1412             :               ;; BUFFER can be nil.  We use a temporary buffer.
    1413           0 :               (generate-new-buffer tramp-temp-buffer-name)))
    1414           0 :            (command (mapconcat 'identity (cons program args) " "))
    1415           0 :            (bmp (and (buffer-live-p buffer) (buffer-modified-p buffer)))
    1416           0 :            (name1 name)
    1417             :            (i 0))
    1418           0 :       (unwind-protect
    1419           0 :           (save-excursion
    1420           0 :             (save-restriction
    1421           0 :               (while (get-process name1)
    1422             :                 ;; NAME must be unique as process name.
    1423           0 :                 (setq i (1+ i)
    1424           0 :                       name1 (format "%s<%d>" name i)))
    1425             :               ;; Set the new process properties.
    1426           0 :               (tramp-set-connection-property v "process-name" name1)
    1427           0 :               (tramp-set-connection-property v "process-buffer" buffer)
    1428             :               ;; Activate narrowing in order to save BUFFER contents.
    1429           0 :               (with-current-buffer (tramp-get-connection-buffer v)
    1430           0 :                 (let ((buffer-undo-list t))
    1431           0 :                   (narrow-to-region (point-max) (point-max))
    1432           0 :                   (tramp-smb-call-winexe v)
    1433           0 :                   (when (tramp-smb-get-share v)
    1434           0 :                     (tramp-smb-send-command
    1435           0 :                      v (format
    1436             :                         "cd \"//%s%s\""
    1437           0 :                         host (file-name-directory localname))))
    1438           0 :                   (tramp-message v 6 "(%s); exit" command)
    1439           0 :                   (tramp-send-string v command)))
    1440             :               ;; Return value.
    1441           0 :               (tramp-get-connection-process v)))
    1442             : 
    1443             :         ;; Save exit.
    1444           0 :         (with-current-buffer (tramp-get-connection-buffer v)
    1445           0 :           (if (string-match tramp-temp-buffer-name (buffer-name))
    1446           0 :               (progn
    1447           0 :                 (set-process-buffer (tramp-get-connection-process v) nil)
    1448           0 :                 (kill-buffer (current-buffer)))
    1449           0 :             (set-buffer-modified-p bmp)))
    1450           0 :         (tramp-set-connection-property v "process-name" nil)
    1451           0 :         (tramp-set-connection-property v "process-buffer" nil)))))
    1452             : 
    1453             : (defun tramp-smb-handle-substitute-in-file-name (filename)
    1454             :   "Like `handle-substitute-in-file-name' for Tramp files.
    1455             : \"//\" substitutes only in the local filename part.  Catches
    1456             : errors for shares like \"C$/\", which are common in Microsoft Windows."
    1457             :   ;; Check, whether the local part is a quoted file name.
    1458           0 :   (if (tramp-compat-file-name-quoted-p filename)
    1459           0 :       filename
    1460           0 :     (with-parsed-tramp-file-name filename nil
    1461             :       ;; Ignore in LOCALNAME everything before "//".
    1462           0 :       (when (and (stringp localname) (string-match ".+?/\\(/\\|~\\)" localname))
    1463           0 :         (setq filename
    1464           0 :               (concat (file-remote-p filename)
    1465           0 :                       (replace-match "\\1" nil nil localname)))))
    1466           0 :     (condition-case nil
    1467           0 :         (tramp-run-real-handler 'substitute-in-file-name (list filename))
    1468           0 :       (error filename))))
    1469             : 
    1470             : (defun tramp-smb-handle-write-region
    1471             :   (start end filename &optional append visit lockname mustbenew)
    1472             :   "Like `write-region' for Tramp files."
    1473           0 :   (setq filename (expand-file-name filename))
    1474           0 :   (with-parsed-tramp-file-name filename nil
    1475           0 :     (when (and mustbenew (file-exists-p filename)
    1476           0 :                (or (eq mustbenew 'excl)
    1477           0 :                    (not
    1478           0 :                     (y-or-n-p
    1479           0 :                      (format "File %s exists; overwrite anyway? " filename)))))
    1480           0 :       (tramp-error v 'file-already-exists filename))
    1481             : 
    1482             :     ;; We must also flush the cache of the directory, because
    1483             :     ;; `file-attributes' reads the values from there.
    1484           0 :     (tramp-flush-file-property v (file-name-directory localname))
    1485           0 :     (tramp-flush-file-property v localname)
    1486           0 :     (let ((curbuf (current-buffer))
    1487           0 :           (tmpfile (tramp-compat-make-temp-file filename)))
    1488           0 :       (when (and append (file-exists-p filename))
    1489           0 :         (copy-file filename tmpfile 'ok))
    1490             :       ;; We say `no-message' here because we don't want the visited file
    1491             :       ;; modtime data to be clobbered from the temp file.  We call
    1492             :       ;; `set-visited-file-modtime' ourselves later on.
    1493           0 :       (tramp-run-real-handler
    1494           0 :        'write-region (list start end tmpfile append 'no-message lockname))
    1495             : 
    1496           0 :       (with-tramp-progress-reporter
    1497           0 :           v 3 (format "Moving tmp file %s to %s" tmpfile filename)
    1498           0 :         (unwind-protect
    1499           0 :             (unless (tramp-smb-send-command
    1500           0 :                      v (format "put %s \"%s\""
    1501           0 :                                tmpfile (tramp-smb-get-localname v)))
    1502           0 :               (tramp-error v 'file-error "Cannot write `%s'" filename))
    1503           0 :           (delete-file tmpfile)))
    1504             : 
    1505           0 :       (unless (equal curbuf (current-buffer))
    1506           0 :         (tramp-error
    1507           0 :          v 'file-error
    1508           0 :          "Buffer has changed from `%s' to `%s'" curbuf (current-buffer)))
    1509           0 :       (when (eq visit t)
    1510           0 :         (set-visited-file-modtime)))))
    1511             : 
    1512             : 
    1513             : ;; Internal file name functions.
    1514             : 
    1515             : (defun tramp-smb-get-share (vec)
    1516             :   "Returns the share name of LOCALNAME."
    1517           0 :   (save-match-data
    1518           0 :     (let ((localname (tramp-file-name-unquote-localname vec)))
    1519           0 :       (when (string-match "^/?\\([^/]+\\)/" localname)
    1520           0 :         (match-string 1 localname)))))
    1521             : 
    1522             : (defun tramp-smb-get-localname (vec)
    1523             :   "Returns the file name of LOCALNAME.
    1524             : If VEC has no cifs capabilities, exchange \"/\" by \"\\\\\"."
    1525           0 :   (save-match-data
    1526           0 :     (let ((localname (tramp-file-name-unquote-localname vec)))
    1527           0 :       (setq
    1528             :        localname
    1529           0 :        (if (string-match "^/?[^/]+\\(/.*\\)" localname)
    1530             :            ;; There is a share, separated by "/".
    1531           0 :            (if (not (tramp-smb-get-cifs-capabilities vec))
    1532           0 :                (mapconcat
    1533           0 :                 (lambda (x) (if (equal x ?/) "\\" (char-to-string x)))
    1534           0 :                 (match-string 1 localname) "")
    1535           0 :              (match-string 1 localname))
    1536             :          ;; There is just a share.
    1537           0 :          (if (string-match "^/?\\([^/]+\\)$" localname)
    1538           0 :              (match-string 1 localname)
    1539           0 :            "")))
    1540             : 
    1541             :       ;; Sometimes we have discarded `substitute-in-file-name'.
    1542           0 :       (when (string-match "\\(\\$\\$\\)\\(/\\|$\\)" localname)
    1543           0 :         (setq localname (replace-match "$" nil nil localname 1)))
    1544             : 
    1545           0 :       localname)))
    1546             : 
    1547             : ;; Share names of a host are cached. It is very unlikely that the
    1548             : ;; shares do change during connection.
    1549             : (defun tramp-smb-get-file-entries (directory)
    1550             :   "Read entries which match DIRECTORY.
    1551             : Either the shares are listed, or the `dir' command is executed.
    1552             : Result is a list of (LOCALNAME MODE SIZE MONTH DAY TIME YEAR)."
    1553           0 :   (with-parsed-tramp-file-name (file-name-as-directory directory) nil
    1554           0 :     (setq localname (or localname "/"))
    1555           0 :     (with-tramp-file-property v localname "file-entries"
    1556           0 :       (with-current-buffer (tramp-get-connection-buffer v)
    1557           0 :         (let* ((share (tramp-smb-get-share v))
    1558           0 :                (cache (tramp-get-connection-property v "share-cache" nil))
    1559             :                res entry)
    1560             : 
    1561           0 :           (if (and (not share) cache)
    1562             :               ;; Return cached shares.
    1563           0 :               (setq res cache)
    1564             : 
    1565             :             ;; Read entries.
    1566           0 :             (if share
    1567           0 :                 (tramp-smb-send-command
    1568           0 :                  v (format "dir \"%s*\"" (tramp-smb-get-localname v)))
    1569             :               ;; `tramp-smb-maybe-open-connection' lists also the share names.
    1570           0 :               (tramp-smb-maybe-open-connection v))
    1571             : 
    1572             :             ;; Loop the listing.
    1573           0 :             (goto-char (point-min))
    1574           0 :             (if (re-search-forward tramp-smb-errors nil t)
    1575           0 :                 (tramp-error v 'file-error "%s `%s'" (match-string 0) directory)
    1576           0 :               (while (not (eobp))
    1577           0 :                 (setq entry (tramp-smb-read-file-entry share))
    1578           0 :                 (forward-line)
    1579           0 :                 (when entry (push entry res))))
    1580             : 
    1581             :             ;; Cache share entries.
    1582           0 :             (unless share
    1583           0 :               (tramp-set-connection-property v "share-cache" res)))
    1584             : 
    1585             :           ;; Add directory itself.
    1586           0 :           (push '("" "drwxrwxrwx" 0 (0 0)) res)
    1587             : 
    1588             :           ;; Return entries.
    1589           0 :           (delq nil res))))))
    1590             : 
    1591             : ;; Return either a share name (if SHARE is nil), or a file name.
    1592             : ;;
    1593             : ;; If shares are listed, the following format is expected:
    1594             : ;;
    1595             : ;; Disk|                                  - leading spaces
    1596             : ;; [^|]+|                                 - share name, 14 char
    1597             : ;; .*                                     - comment
    1598             : ;;
    1599             : ;; Entries provided by smbclient DIR aren't fully regular.
    1600             : ;; They should have the format
    1601             : ;;
    1602             : ;; \s-\{2,2}                              - leading spaces
    1603             : ;; \S-\(.*\S-\)\s-*                       - file name, 30 chars, left bound
    1604             : ;; \s-+[ADHRSV]*                          - permissions, 7 chars, right bound
    1605             : ;; \s-                                    - space delimiter
    1606             : ;; \s-+[0-9]+                             - size, 8 chars, right bound
    1607             : ;; \s-\{2,2\}                             - space delimiter
    1608             : ;; \w\{3,3\}                              - weekday
    1609             : ;; \s-                                    - space delimiter
    1610             : ;; \w\{3,3\}                              - month
    1611             : ;; \s-                                    - space delimiter
    1612             : ;; [ 12][0-9]                             - day
    1613             : ;; \s-                                    - space delimiter
    1614             : ;; [0-9]\{2,2\}:[0-9]\{2,2\}:[0-9]\{2,2\} - time
    1615             : ;; \s-                                    - space delimiter
    1616             : ;; [0-9]\{4,4\}                           - year
    1617             : ;;
    1618             : ;; samba/src/client.c (http://samba.org/doxygen/samba/client_8c-source.html)
    1619             : ;; has function display_finfo:
    1620             : ;;
    1621             : ;;   d_printf("  %-30s%7.7s %8.0f  %s",
    1622             : ;;            finfo->name,
    1623             : ;;            attrib_string(finfo->mode),
    1624             : ;;            (double)finfo->size,
    1625             : ;;            asctime(LocalTime(&t)));
    1626             : ;;
    1627             : ;; in Samba 1.9, there's the following code:
    1628             : ;;
    1629             : ;;   DEBUG(0,("  %-30s%7.7s%10d  %s",
    1630             : ;;         CNV_LANG(finfo->name),
    1631             : ;;         attrib_string(finfo->mode),
    1632             : ;;         finfo->size,
    1633             : ;;         asctime(LocalTime(&t))));
    1634             : ;;
    1635             : ;; Problems:
    1636             : ;; * Modern regexp constructs, like spy groups and counted repetitions, aren't
    1637             : ;;   available in older Emacsen.
    1638             : ;; * The length of constructs (file name, size) might exceed the default.
    1639             : ;; * File names might contain spaces.
    1640             : ;; * Permissions might be empty.
    1641             : ;;
    1642             : ;; So we try to analyze backwards.
    1643             : (defun tramp-smb-read-file-entry (share)
    1644             :   "Parse entry in SMB output buffer.
    1645             : If SHARE is result, entries are of type dir. Otherwise, shares are listed.
    1646             : Result is the list (LOCALNAME MODE SIZE MTIME)."
    1647             : ;; We are called from `tramp-smb-get-file-entries', which sets the
    1648             : ;; current buffer.
    1649           0 :   (let ((line (buffer-substring (point) (point-at-eol)))
    1650             :         localname mode size month day hour min sec year mtime)
    1651             : 
    1652           0 :     (if (not share)
    1653             : 
    1654             :         ;; Read share entries.
    1655           0 :         (when (string-match "^Disk|\\([^|]+\\)|" line)
    1656           0 :           (setq localname (match-string 1 line)
    1657             :                 mode "dr-xr-xr-x"
    1658           0 :                 size 0))
    1659             : 
    1660             :       ;; Real listing.
    1661           0 :       (cl-block nil
    1662             : 
    1663             :         ;; year.
    1664           0 :         (if (string-match "\\([0-9]+\\)$" line)
    1665           0 :             (setq year (string-to-number (match-string 1 line))
    1666           0 :                   line (substring line 0 -5))
    1667           0 :           (cl-return))
    1668             : 
    1669             :         ;; time.
    1670           0 :         (if (string-match "\\([0-9]+\\):\\([0-9]+\\):\\([0-9]+\\)$" line)
    1671           0 :             (setq hour (string-to-number (match-string 1 line))
    1672           0 :                   min  (string-to-number (match-string 2 line))
    1673           0 :                   sec  (string-to-number (match-string 3 line))
    1674           0 :                   line (substring line 0 -9))
    1675           0 :           (cl-return))
    1676             : 
    1677             :         ;; day.
    1678           0 :         (if (string-match "\\([0-9]+\\)$" line)
    1679           0 :             (setq day  (string-to-number (match-string 1 line))
    1680           0 :                   line (substring line 0 -3))
    1681           0 :           (cl-return))
    1682             : 
    1683             :         ;; month.
    1684           0 :         (if (string-match "\\(\\w+\\)$" line)
    1685           0 :             (setq month (match-string 1 line)
    1686           0 :                   line  (substring line 0 -4))
    1687           0 :           (cl-return))
    1688             : 
    1689             :         ;; weekday.
    1690           0 :         (if (string-match "\\(\\w+\\)$" line)
    1691           0 :             (setq line (substring line 0 -5))
    1692           0 :           (cl-return))
    1693             : 
    1694             :         ;; size.
    1695           0 :         (if (string-match "\\([0-9]+\\)$" line)
    1696           0 :             (let ((length (- (max 10 (1+ (length (match-string 1 line)))))))
    1697           0 :               (setq size (string-to-number (match-string 1 line)))
    1698           0 :               (when (string-match "\\([ADHRSV]+\\)" (substring line length))
    1699           0 :                 (setq length (+ length (match-end 0))))
    1700           0 :               (setq line (substring line 0 length)))
    1701           0 :           (cl-return))
    1702             : 
    1703             :         ;; mode: ARCH, DIR, HIDDEN, RONLY, SYSTEM, VOLID.
    1704           0 :         (if (string-match "\\([ADHRSV]+\\)?$" line)
    1705           0 :             (setq
    1706           0 :              mode (or (match-string 1 line) "")
    1707           0 :              mode (save-match-data (format
    1708             :                     "%s%s"
    1709           0 :                     (if (string-match "D" mode) "d" "-")
    1710           0 :                     (mapconcat
    1711             :                      (lambda (_x) "") "    "
    1712           0 :                      (concat "r" (if (string-match "R" mode) "-" "w") "x"))))
    1713           0 :              line (substring line 0 -6))
    1714           0 :           (cl-return))
    1715             : 
    1716             :         ;; localname.
    1717           0 :         (if (string-match "^\\s-+\\(\\S-\\(.*\\S-\\)?\\)\\s-*$" line)
    1718           0 :             (setq localname (match-string 1 line))
    1719           0 :           (cl-return))))
    1720             : 
    1721           0 :     (when (and localname mode size)
    1722           0 :       (setq mtime
    1723           0 :             (if (and sec min hour day month year)
    1724           0 :                 (encode-time
    1725           0 :                  sec min hour day
    1726           0 :                  (cdr (assoc (downcase month) parse-time-months))
    1727           0 :                  year)
    1728           0 :               '(0 0)))
    1729           0 :       (list localname mode size mtime))))
    1730             : 
    1731             : (defun tramp-smb-get-cifs-capabilities (vec)
    1732             :   "Check, whether the SMB server supports POSIX commands."
    1733             :   ;; When we are not logged in yet, we return nil.
    1734           0 :   (if (process-live-p (tramp-get-connection-process vec))
    1735           0 :       (with-tramp-connection-property
    1736           0 :           (tramp-get-connection-process vec) "cifs-capabilities"
    1737           0 :         (save-match-data
    1738           0 :           (when (tramp-smb-send-command vec "posix")
    1739           0 :             (with-current-buffer (tramp-get-connection-buffer vec)
    1740           0 :               (goto-char (point-min))
    1741           0 :               (when
    1742           0 :                   (re-search-forward "Server supports CIFS capabilities" nil t)
    1743           0 :                 (member
    1744             :                  "pathnames"
    1745           0 :                  (split-string
    1746           0 :                   (buffer-substring (point) (point-at-eol)) nil 'omit)))))))))
    1747             : 
    1748             : (defun tramp-smb-get-stat-capability (vec)
    1749             :   "Check, whether the SMB server supports the STAT command."
    1750             :   ;; When we are not logged in yet, we return nil.
    1751           0 :   (if (and (tramp-smb-get-share vec)
    1752           0 :            (process-live-p (tramp-get-connection-process vec)))
    1753           0 :       (with-tramp-connection-property
    1754           0 :           (tramp-get-connection-process vec) "stat-capability"
    1755           0 :         (tramp-smb-send-command vec "stat \"/\""))))
    1756             : 
    1757             : 
    1758             : ;; Connection functions.
    1759             : 
    1760             : (defun tramp-smb-send-command (vec command)
    1761             :   "Send the COMMAND to connection VEC.
    1762             : Returns nil if there has been an error message from smbclient."
    1763           0 :   (tramp-smb-maybe-open-connection vec)
    1764           0 :   (tramp-message vec 6 "%s" command)
    1765           0 :   (tramp-send-string vec command)
    1766           0 :   (tramp-smb-wait-for-output vec))
    1767             : 
    1768             : (defun tramp-smb-maybe-open-connection (vec &optional argument)
    1769             :   "Maybe open a connection to HOST, log in as USER, using `tramp-smb-program'.
    1770             : Does not do anything if a connection is already open, but re-opens the
    1771             : connection if a previous connection has died for some reason.
    1772             : If ARGUMENT is non-nil, use it as argument for
    1773             : `tramp-smb-winexe-program', and suppress any checks."
    1774           0 :   (let* ((share (tramp-smb-get-share vec))
    1775           0 :          (buf (tramp-get-connection-buffer vec))
    1776           0 :          (p (get-buffer-process buf)))
    1777             : 
    1778             :     ;; Check whether we still have the same smbclient version.
    1779             :     ;; Otherwise, we must delete the connection cache, because
    1780             :     ;; capabilities migh have changed.
    1781           0 :     (unless (or argument (processp p))
    1782           0 :       (let ((default-directory (tramp-compat-temporary-file-directory))
    1783           0 :             (command (concat tramp-smb-program " -V")))
    1784             : 
    1785           0 :         (unless tramp-smb-version
    1786           0 :           (unless (executable-find tramp-smb-program)
    1787           0 :             (tramp-error
    1788           0 :              vec 'file-error
    1789           0 :              "Cannot find command %s in %s" tramp-smb-program exec-path))
    1790           0 :           (setq tramp-smb-version (shell-command-to-string command))
    1791           0 :           (tramp-message vec 6 command)
    1792           0 :           (tramp-message vec 6 "\n%s" tramp-smb-version)
    1793           0 :           (if (string-match "[ \t\n\r]+\\'" tramp-smb-version)
    1794           0 :               (setq tramp-smb-version
    1795           0 :                     (replace-match "" nil nil tramp-smb-version))))
    1796             : 
    1797           0 :         (unless (string-equal
    1798           0 :                  tramp-smb-version
    1799           0 :                  (tramp-get-connection-property
    1800           0 :                   vec "smbclient-version" tramp-smb-version))
    1801           0 :           (tramp-flush-directory-property vec "")
    1802           0 :           (tramp-flush-connection-property vec))
    1803             : 
    1804           0 :         (tramp-set-connection-property
    1805           0 :          vec "smbclient-version" tramp-smb-version)))
    1806             : 
    1807             :     ;; If too much time has passed since last command was sent, look
    1808             :     ;; whether there has been an error message; maybe due to
    1809             :     ;; connection timeout.
    1810           0 :     (with-current-buffer buf
    1811           0 :       (goto-char (point-min))
    1812           0 :       (when (and (> (tramp-time-diff
    1813           0 :                      (current-time)
    1814           0 :                      (tramp-get-connection-property
    1815           0 :                       p "last-cmd-time" '(0 0 0)))
    1816           0 :                     60)
    1817           0 :                  (process-live-p p)
    1818           0 :                  (re-search-forward tramp-smb-errors nil t))
    1819           0 :         (delete-process p)
    1820           0 :         (setq p nil)))
    1821             : 
    1822             :     ;; Check whether it is still the same share.
    1823           0 :     (unless (and (process-live-p p)
    1824           0 :                  (or argument
    1825           0 :                      (string-equal
    1826           0 :                       share
    1827           0 :                       (tramp-get-connection-property p "smb-share" ""))))
    1828             : 
    1829           0 :       (save-match-data
    1830             :         ;; There might be unread output from checking for share names.
    1831           0 :         (when buf (with-current-buffer buf (erase-buffer)))
    1832           0 :         (when (and p (processp p)) (delete-process p))
    1833             : 
    1834           0 :         (let* ((user   (tramp-file-name-user vec))
    1835           0 :                (host   (tramp-file-name-host vec))
    1836           0 :                (domain (tramp-file-name-domain vec))
    1837           0 :                (port   (tramp-file-name-port vec))
    1838             :                args)
    1839             : 
    1840           0 :           (cond
    1841           0 :            (argument
    1842           0 :             (setq args (list (concat "//" host))))
    1843           0 :            (share
    1844           0 :             (setq args (list (concat "//" host "/" share))))
    1845             :            (t
    1846           0 :             (setq args (list "-g" "-L" host ))))
    1847             : 
    1848           0 :           (if (not (zerop (length user)))
    1849           0 :               (setq args (append args (list "-U" user)))
    1850           0 :             (setq args (append args (list "-N"))))
    1851             : 
    1852           0 :           (when domain (setq args (append args (list "-W" domain))))
    1853           0 :           (when port   (setq args (append args (list "-p" port))))
    1854           0 :           (when tramp-smb-conf
    1855           0 :             (setq args (append args (list "-s" tramp-smb-conf))))
    1856           0 :           (when argument
    1857           0 :             (setq args (append args (list argument))))
    1858             : 
    1859             :           ;; OK, let's go.
    1860           0 :           (with-tramp-progress-reporter
    1861           0 :               vec 3
    1862           0 :               (format "Opening connection for //%s%s/%s"
    1863           0 :                       (if (not (zerop (length user))) (concat user "@") "")
    1864           0 :                       host (or share ""))
    1865             : 
    1866           0 :             (let* ((coding-system-for-read nil)
    1867           0 :                    (process-connection-type tramp-process-connection-type)
    1868           0 :                    (p (let ((default-directory
    1869           0 :                               (tramp-compat-temporary-file-directory)))
    1870           0 :                         (apply #'start-process
    1871           0 :                                (tramp-get-connection-name vec)
    1872           0 :                                (tramp-get-connection-buffer vec)
    1873           0 :                                (if argument
    1874           0 :                                    tramp-smb-winexe-program tramp-smb-program)
    1875           0 :                                args))))
    1876             : 
    1877           0 :               (tramp-message
    1878           0 :                vec 6 "%s" (mapconcat 'identity (process-command p) " "))
    1879           0 :               (tramp-set-connection-property p "vector" vec)
    1880           0 :               (process-put p 'adjust-window-size-function 'ignore)
    1881           0 :               (set-process-query-on-exit-flag p nil)
    1882             : 
    1883             :               ;; Set variables for computing the prompt for reading password.
    1884           0 :               (setq tramp-current-method tramp-smb-method
    1885           0 :                     tramp-current-user user
    1886           0 :                     tramp-current-domain domain
    1887           0 :                     tramp-current-host host
    1888           0 :                     tramp-current-port port)
    1889             : 
    1890           0 :               (condition-case err
    1891           0 :                   (let (tramp-message-show-message)
    1892             :                     ;; Play login scenario.
    1893           0 :                     (tramp-process-actions
    1894           0 :                      p vec nil
    1895           0 :                      (if (or argument share)
    1896           0 :                          tramp-smb-actions-with-share
    1897           0 :                        tramp-smb-actions-without-share))
    1898             : 
    1899             :                     ;; Check server version.
    1900           0 :                     (unless argument
    1901           0 :                       (with-current-buffer (tramp-get-connection-buffer vec)
    1902           0 :                         (goto-char (point-min))
    1903           0 :                         (search-forward-regexp tramp-smb-server-version nil t)
    1904           0 :                         (let ((smbserver-version (match-string 0)))
    1905           0 :                           (unless
    1906           0 :                               (string-equal
    1907           0 :                                smbserver-version
    1908           0 :                                (tramp-get-connection-property
    1909           0 :                                 vec "smbserver-version" smbserver-version))
    1910           0 :                             (tramp-flush-directory-property vec "")
    1911           0 :                             (tramp-flush-connection-property vec))
    1912           0 :                           (tramp-set-connection-property
    1913           0 :                            vec "smbserver-version" smbserver-version))))
    1914             : 
    1915             :                     ;; Set chunksize to 1.  smbclient reads its input
    1916             :                     ;; character by character; if we send the string
    1917             :                     ;; at once, it is read painfully slow.
    1918           0 :                     (tramp-set-connection-property p "smb-share" share)
    1919           0 :                     (tramp-set-connection-property p "chunksize" 1)
    1920             : 
    1921             :                     ;; Set connection-local variables.
    1922           0 :                     (tramp-set-connection-local-variables vec)
    1923             : 
    1924             :                     ;; Mark it as connected.
    1925           0 :                     (tramp-set-connection-property p "connected" t))
    1926             : 
    1927             :                 ;; Check for the error reason.  If it was due to wrong
    1928             :                 ;; password, reestablish the connection.  We cannot
    1929             :                 ;; handle this in `tramp-process-actions', because
    1930             :                 ;; smbclient does not ask for the password, again.
    1931             :                 (error
    1932           0 :                  (with-current-buffer (tramp-get-connection-buffer vec)
    1933           0 :                    (goto-char (point-min))
    1934           0 :                    (if (and (bound-and-true-p auth-sources)
    1935           0 :                             (search-forward-regexp
    1936           0 :                              tramp-smb-wrong-passwd-regexp nil t))
    1937             :                        ;; Disable `auth-source' and `password-cache'.
    1938           0 :                        (let (auth-sources)
    1939           0 :                          (tramp-message
    1940           0 :                           vec 3 "Retry connection with new password")
    1941           0 :                          (tramp-cleanup-connection vec t)
    1942           0 :                          (tramp-smb-maybe-open-connection vec argument))
    1943             :                      ;; Propagate the error.
    1944           0 :                      (signal (car err) (cdr err)))))))))))))
    1945             : 
    1946             : ;; We don't use timeouts.  If needed, the caller shall wrap around.
    1947             : (defun tramp-smb-wait-for-output (vec)
    1948             :   "Wait for output from smbclient command.
    1949             : Returns nil if an error message has appeared."
    1950           0 :   (with-current-buffer (tramp-get-connection-buffer vec)
    1951           0 :     (let ((p (get-buffer-process (current-buffer)))
    1952           0 :           (found (progn (goto-char (point-min))
    1953           0 :                         (re-search-forward tramp-smb-prompt nil t)))
    1954           0 :           (err   (progn (goto-char (point-min))
    1955           0 :                         (re-search-forward tramp-smb-errors nil t)))
    1956             :           buffer-read-only)
    1957             : 
    1958             :       ;; Algorithm: get waiting output.  See if last line contains
    1959             :       ;; `tramp-smb-prompt' sentinel or `tramp-smb-errors' strings.
    1960             :       ;; If not, wait a bit and again get waiting output.
    1961           0 :       (while (and (not found) (not err) (process-live-p p))
    1962             : 
    1963             :         ;; Accept pending output.
    1964           0 :         (tramp-accept-process-output p 0.1)
    1965             : 
    1966             :         ;; Search for prompt.
    1967           0 :         (goto-char (point-min))
    1968           0 :         (setq found (re-search-forward tramp-smb-prompt nil t))
    1969             : 
    1970             :         ;; Search for errors.
    1971           0 :         (goto-char (point-min))
    1972           0 :         (setq err (re-search-forward tramp-smb-errors nil t)))
    1973             : 
    1974             :       ;; When the process is still alive, read pending output.
    1975           0 :       (while (and (not found) (process-live-p p))
    1976             : 
    1977             :         ;; Accept pending output.
    1978           0 :         (tramp-accept-process-output p 0.1)
    1979             : 
    1980             :         ;; Search for prompt.
    1981           0 :         (goto-char (point-min))
    1982           0 :         (setq found (re-search-forward tramp-smb-prompt nil t)))
    1983             : 
    1984           0 :       (tramp-message vec 6 "\n%s" (buffer-string))
    1985             : 
    1986             :       ;; Remove prompt.
    1987           0 :       (when found
    1988           0 :         (goto-char (point-max))
    1989           0 :         (re-search-backward tramp-smb-prompt nil t)
    1990           0 :         (delete-region (point) (point-max)))
    1991             : 
    1992             :       ;; Return value is whether no error message has appeared.
    1993           0 :       (not err))))
    1994             : 
    1995             : (defun tramp-smb-kill-winexe-function ()
    1996             :   "Send SIGKILL to the winexe process."
    1997           0 :   (ignore-errors
    1998           0 :     (let ((p (get-buffer-process (current-buffer))))
    1999           0 :       (when (process-live-p p)
    2000           0 :         (signal-process (process-id p) 'SIGINT)))))
    2001             : 
    2002             : (defun tramp-smb-call-winexe (vec)
    2003             :   "Apply a remote command, if possible, using `tramp-smb-winexe-program'."
    2004             : 
    2005             :   ;; Check for program.
    2006           0 :   (unless (executable-find tramp-smb-winexe-program)
    2007           0 :     (tramp-error
    2008           0 :      vec 'file-error "Cannot find program: %s" tramp-smb-winexe-program))
    2009             : 
    2010             :   ;; winexe does not supports ports.
    2011           0 :   (when (tramp-file-name-port vec)
    2012           0 :     (tramp-error vec 'file-error "Port not supported for remote processes"))
    2013             : 
    2014           0 :   (tramp-smb-maybe-open-connection
    2015           0 :    vec
    2016           0 :    (format
    2017             :     "%s %s"
    2018           0 :     tramp-smb-winexe-shell-command tramp-smb-winexe-shell-command-switch))
    2019             : 
    2020           0 :   (set (make-local-variable 'kill-buffer-hook)
    2021           0 :        '(tramp-smb-kill-winexe-function))
    2022             : 
    2023             :   ;; Suppress "^M".  Shouldn't we specify utf8?
    2024           0 :   (set-process-coding-system (tramp-get-connection-process vec) 'raw-text-dos)
    2025             : 
    2026             :   ;; Set width to 128.  This avoids mixing prompt and long error messages.
    2027           0 :   (tramp-smb-send-command vec "$rawui = (Get-Host).UI.RawUI")
    2028           0 :   (tramp-smb-send-command vec "$bufsize = $rawui.BufferSize")
    2029           0 :   (tramp-smb-send-command vec "$winsize = $rawui.WindowSize")
    2030           0 :   (tramp-smb-send-command vec "$bufsize.Width = 128")
    2031           0 :   (tramp-smb-send-command vec "$winsize.Width = 128")
    2032           0 :   (tramp-smb-send-command vec "$rawui.BufferSize = $bufsize")
    2033           0 :   (tramp-smb-send-command vec "$rawui.WindowSize = $winsize"))
    2034             : 
    2035             : (defun tramp-smb-shell-quote-argument (s)
    2036             :   "Similar to `shell-quote-argument', but uses windows cmd syntax."
    2037           0 :   (let ((system-type 'ms-dos))
    2038           0 :     (tramp-unquote-shell-quote-argument s)))
    2039             : 
    2040             : (add-hook 'tramp-unload-hook
    2041             :           (lambda ()
    2042             :             (unload-feature 'tramp-smb 'force)))
    2043             : 
    2044             : (provide 'tramp-smb)
    2045             : 
    2046             : ;;; TODO:
    2047             : 
    2048             : ;; * Return more comprehensive file permission string.
    2049             : ;;
    2050             : ;; * Try to remove the inclusion of dummy "" directory.  Seems to be at
    2051             : ;;   several places, especially in `tramp-smb-handle-insert-directory'.
    2052             : ;;
    2053             : ;; * Ignore case in file names.
    2054             : 
    2055             : ;;; tramp-smb.el ends here

Generated by: LCOV version 1.12