tramp-smb.el 65 KB

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