comparison lisp/net/tramp-smb.el @ 105509:69bf209a4707

* net/tramp-smb.el (tramp-smb-errors): Add error messages. (tramp-smb-file-name-handler-alist): Add handler for `copy-directory', `expand-file-name', `set-file-modes'. (tramp-smb-handle-copy-directory) (tramp-smb-handle-expand-file-name) (tramp-smb-handle-set-file-modes): New defuns. (tramp-smb-handle-copy-file): Handle KEPP-DATE. (tramp-smb-handle-file-attributes): Simplify check for retrieving entry. (tramp-smb-handle-insert-directory): Don't flush the cache. (tramp-smb-maybe-open-connection): Check for samba client and server versions.
author Michael Albinus <michael.albinus@gmx.de>
date Wed, 07 Oct 2009 11:30:19 +0000
parents 56aa7f20f7da
children e781cac84553
comparison
equal deleted inserted replaced
105508:3b3d1d59e375 105509:69bf209a4707
66 66
67 (defconst tramp-smb-errors 67 (defconst tramp-smb-errors
68 ;; `regexp-opt' not possible because of first string. 68 ;; `regexp-opt' not possible because of first string.
69 (mapconcat 69 (mapconcat
70 'identity 70 'identity
71 '(;; Connection error / timeout 71 '(;; Connection error / timeout / unknown command.
72 "Connection to \\S-+ failed" 72 "Connection to \\S-+ failed"
73 "Read from server failed, maybe it closed the connection" 73 "Read from server failed, maybe it closed the connection"
74 "Call timed out: server did not respond" 74 "Call timed out: server did not respond"
75 ;; Samba 75 "\\S-+: command not found"
76 "Server doesn't support UNIX CIFS calls"
77 ;; Samba.
76 "ERRDOS" 78 "ERRDOS"
77 "ERRSRV" 79 "ERRSRV"
78 "ERRbadfile" 80 "ERRbadfile"
79 "ERRbadpw" 81 "ERRbadpw"
80 "ERRfilexists" 82 "ERRfilexists"
81 "ERRnoaccess" 83 "ERRnoaccess"
82 "ERRnomem" 84 "ERRnomem"
83 "ERRnosuchshare" 85 "ERRnosuchshare"
84 ;; Windows 4.0 (Windows NT), Windows 5.0 (Windows 2000), 86 ;; Windows 4.0 (Windows NT), Windows 5.0 (Windows 2000),
85 ;; Windows 5.1 (Windows XP), Windows 5.2 (Windows Server 2003) 87 ;; Windows 5.1 (Windows XP), Windows 5.2 (Windows Server 2003).
86 "NT_STATUS_ACCESS_DENIED" 88 "NT_STATUS_ACCESS_DENIED"
87 "NT_STATUS_ACCOUNT_LOCKED_OUT" 89 "NT_STATUS_ACCOUNT_LOCKED_OUT"
88 "NT_STATUS_BAD_NETWORK_NAME" 90 "NT_STATUS_BAD_NETWORK_NAME"
89 "NT_STATUS_CANNOT_DELETE" 91 "NT_STATUS_CANNOT_DELETE"
90 "NT_STATUS_CONNECTION_REFUSED" 92 "NT_STATUS_CONNECTION_REFUSED"
126 See `tramp-actions-before-shell' for more info.") 128 See `tramp-actions-before-shell' for more info.")
127 129
128 ;; New handlers should be added here. 130 ;; New handlers should be added here.
129 (defconst tramp-smb-file-name-handler-alist 131 (defconst tramp-smb-file-name-handler-alist
130 '( 132 '(
131 ;; `access-file' performed by default handler 133 ;; `access-file' performed by default handler.
132 (add-name-to-file . tramp-smb-handle-copy-file) ;; we're on Windows, honey. 134 (add-name-to-file . tramp-smb-handle-copy-file) ;; we're on Windows, honey.
133 ;; `byte-compiler-base-file-name' performed by default handler 135 ;; `byte-compiler-base-file-name' performed by default handler.
136 (copy-directory . tramp-smb-handle-copy-directory)
134 (copy-file . tramp-smb-handle-copy-file) 137 (copy-file . tramp-smb-handle-copy-file)
135 (delete-directory . tramp-smb-handle-delete-directory) 138 (delete-directory . tramp-smb-handle-delete-directory)
136 (delete-file . tramp-smb-handle-delete-file) 139 (delete-file . tramp-smb-handle-delete-file)
137 ;; `diff-latest-backup-file' performed by default handler 140 ;; `diff-latest-backup-file' performed by default handler.
138 (directory-file-name . tramp-handle-directory-file-name) 141 (directory-file-name . tramp-handle-directory-file-name)
139 (directory-files . tramp-smb-handle-directory-files) 142 (directory-files . tramp-smb-handle-directory-files)
140 (directory-files-and-attributes . tramp-smb-handle-directory-files-and-attributes) 143 (directory-files-and-attributes
144 . tramp-smb-handle-directory-files-and-attributes)
141 (dired-call-process . ignore) 145 (dired-call-process . ignore)
142 (dired-compress-file . ignore) 146 (dired-compress-file . ignore)
143 (dired-uncache . tramp-handle-dired-uncache) 147 (dired-uncache . tramp-handle-dired-uncache)
144 ;; `expand-file-name' not necessary because we cannot expand "~/" 148 (expand-file-name . tramp-smb-handle-expand-file-name)
145 (file-accessible-directory-p . tramp-smb-handle-file-directory-p) 149 (file-accessible-directory-p . tramp-smb-handle-file-directory-p)
146 (file-attributes . tramp-smb-handle-file-attributes) 150 (file-attributes . tramp-smb-handle-file-attributes)
147 (file-directory-p . tramp-smb-handle-file-directory-p) 151 (file-directory-p . tramp-smb-handle-file-directory-p)
148 (file-executable-p . tramp-smb-handle-file-exists-p) 152 (file-executable-p . tramp-smb-handle-file-exists-p)
149 (file-exists-p . tramp-smb-handle-file-exists-p) 153 (file-exists-p . tramp-smb-handle-file-exists-p)
153 (file-name-all-completions . tramp-smb-handle-file-name-all-completions) 157 (file-name-all-completions . tramp-smb-handle-file-name-all-completions)
154 (file-name-as-directory . tramp-handle-file-name-as-directory) 158 (file-name-as-directory . tramp-handle-file-name-as-directory)
155 (file-name-completion . tramp-handle-file-name-completion) 159 (file-name-completion . tramp-handle-file-name-completion)
156 (file-name-directory . tramp-handle-file-name-directory) 160 (file-name-directory . tramp-handle-file-name-directory)
157 (file-name-nondirectory . tramp-handle-file-name-nondirectory) 161 (file-name-nondirectory . tramp-handle-file-name-nondirectory)
158 ;; `file-name-sans-versions' performed by default handler 162 ;; `file-name-sans-versions' performed by default handler.
159 (file-newer-than-file-p . tramp-smb-handle-file-newer-than-file-p) 163 (file-newer-than-file-p . tramp-smb-handle-file-newer-than-file-p)
160 (file-ownership-preserved-p . ignore) 164 (file-ownership-preserved-p . ignore)
161 (file-readable-p . tramp-smb-handle-file-exists-p) 165 (file-readable-p . tramp-smb-handle-file-exists-p)
162 (file-regular-p . tramp-handle-file-regular-p) 166 (file-regular-p . tramp-handle-file-regular-p)
163 (file-symlink-p . tramp-handle-file-symlink-p) 167 (file-symlink-p . tramp-handle-file-symlink-p)
164 ;; `file-truename' performed by default handler 168 ;; `file-truename' performed by default handler.
165 (file-writable-p . tramp-smb-handle-file-writable-p) 169 (file-writable-p . tramp-smb-handle-file-writable-p)
166 (find-backup-file-name . tramp-handle-find-backup-file-name) 170 (find-backup-file-name . tramp-handle-find-backup-file-name)
167 ;; `find-file-noselect' performed by default handler 171 ;; `find-file-noselect' performed by default handler.
168 ;; `get-file-buffer' performed by default handler 172 ;; `get-file-buffer' performed by default handler.
169 (insert-directory . tramp-smb-handle-insert-directory) 173 (insert-directory . tramp-smb-handle-insert-directory)
170 (insert-file-contents . tramp-handle-insert-file-contents) 174 (insert-file-contents . tramp-handle-insert-file-contents)
171 (load . tramp-handle-load) 175 (load . tramp-handle-load)
172 (make-directory . tramp-smb-handle-make-directory) 176 (make-directory . tramp-smb-handle-make-directory)
173 (make-directory-internal . tramp-smb-handle-make-directory-internal) 177 (make-directory-internal . tramp-smb-handle-make-directory-internal)
174 (make-symbolic-link . ignore) 178 (make-symbolic-link . ignore)
175 (rename-file . tramp-smb-handle-rename-file) 179 (rename-file . tramp-smb-handle-rename-file)
176 (set-file-modes . ignore) 180 (set-file-modes . tramp-smb-handle-set-file-modes)
181 (set-file-times . ignore)
177 (set-visited-file-modtime . ignore) 182 (set-visited-file-modtime . ignore)
178 (shell-command . ignore) 183 (shell-command . ignore)
179 (substitute-in-file-name . tramp-smb-handle-substitute-in-file-name) 184 (substitute-in-file-name . tramp-smb-handle-substitute-in-file-name)
180 (unhandled-file-name-directory . tramp-handle-unhandled-file-name-directory) 185 (unhandled-file-name-directory . tramp-handle-unhandled-file-name-directory)
181 (vc-registered . ignore) 186 (vc-registered . ignore)
201 206
202 (add-to-list 'tramp-foreign-file-name-handler-alist 207 (add-to-list 'tramp-foreign-file-name-handler-alist
203 (cons 'tramp-smb-file-name-p 'tramp-smb-file-name-handler)) 208 (cons 'tramp-smb-file-name-p 'tramp-smb-file-name-handler))
204 209
205 210
206 ;; File name primitives 211 ;; File name primitives.
212
213 (defun tramp-smb-handle-copy-directory
214 (dirname newname &optional keep-date parents)
215 "Like `copy-directory' for Tramp files."
216 (setq dirname (expand-file-name dirname)
217 newname (expand-file-name newname))
218 (let ((t1 (tramp-tramp-file-p dirname))
219 (t2 (tramp-tramp-file-p newname)))
220 (with-parsed-tramp-file-name (if t1 dirname newname) nil
221 (if (or (null t1) (null t2))
222 ;; We can copy recursively.
223 (let ((prompt (tramp-smb-send-command v "prompt"))
224 (recurse (tramp-smb-send-command v "recurse")))
225 (unless (file-directory-p newname)
226 (make-directory newname parents))
227 (unwind-protect
228 (unless
229 (and
230 prompt recurse
231 (tramp-smb-send-command
232 v (format "cd \"%s\""
233 (tramp-smb-get-localname localname t)))
234 (tramp-smb-send-command
235 v (format "lcd \"%s\"" (if t1 newname dirname)))
236 (if t1
237 (tramp-smb-send-command v "mget *")
238 (tramp-smb-send-command v "mput *")))
239 ;; Error.
240 (with-current-buffer (tramp-get-connection-buffer v)
241 (goto-char (point-min))
242 (search-forward-regexp tramp-smb-errors nil t)
243 (tramp-error
244 v 'file-error
245 "%s `%s'" (match-string 0) (if t1 dirname newname))))
246 ;; Always go home.
247 (tramp-smb-send-command v (format "cd \\"))
248 ;; Toggle prompt and recurse OFF.
249 (if prompt (tramp-smb-send-command v "prompt"))
250 (if recurse (tramp-smb-send-command v "recurse"))))
251
252 ;; We must do it file-wise.
253 (tramp-run-real-handler
254 'copy-directory (list dirname newname keep-date parents))))))
207 255
208 (defun tramp-smb-handle-copy-file 256 (defun tramp-smb-handle-copy-file
209 (filename newname &optional ok-if-already-exists keep-date preserve-uid-gid) 257 (filename newname &optional ok-if-already-exists keep-date preserve-uid-gid)
210 "Like `copy-file' for Tramp files. 258 "Like `copy-file' for Tramp files.
211 KEEP-DATE is not handled in case NEWNAME resides on an SMB server. 259 KEEP-DATE is not handled in case NEWNAME resides on an SMB server.
245 (tramp-message v 0 "Copying file %s to file %s..." filename newname) 293 (tramp-message v 0 "Copying file %s to file %s..." filename newname)
246 (if (tramp-smb-send-command 294 (if (tramp-smb-send-command
247 v (format "put %s \"%s\"" filename file)) 295 v (format "put %s \"%s\"" filename file))
248 (tramp-message 296 (tramp-message
249 v 0 "Copying file %s to file %s...done" filename newname) 297 v 0 "Copying file %s to file %s...done" filename newname)
250 (tramp-error v 'file-error "Cannot copy `%s'" filename))))))) 298 (tramp-error v 'file-error "Cannot copy `%s'" filename))))))
299
300 ;; KEEP-DATE handling.
301 (when keep-date (set-file-times newname (nth 5 (file-attributes filename)))))
251 302
252 (defun tramp-smb-handle-delete-directory (directory &optional recursive) 303 (defun tramp-smb-handle-delete-directory (directory &optional recursive)
253 "Like `delete-directory' for Tramp files." 304 "Like `delete-directory' for Tramp files."
254 (setq directory (directory-file-name (expand-file-name directory))) 305 (setq directory (directory-file-name (expand-file-name directory)))
255 (when (file-exists-p directory) 306 (when (file-exists-p directory)
271 (file (file-name-nondirectory localname))) 322 (file (file-name-nondirectory localname)))
272 (unwind-protect 323 (unwind-protect
273 (unless (and 324 (unless (and
274 (tramp-smb-send-command v (format "cd \"%s\"" dir)) 325 (tramp-smb-send-command v (format "cd \"%s\"" dir))
275 (tramp-smb-send-command v (format "rmdir \"%s\"" file))) 326 (tramp-smb-send-command v (format "rmdir \"%s\"" file)))
276 ;; Error 327 ;; Error.
277 (with-current-buffer (tramp-get-connection-buffer v) 328 (with-current-buffer (tramp-get-connection-buffer v)
278 (goto-char (point-min)) 329 (goto-char (point-min))
279 (search-forward-regexp tramp-smb-errors nil t) 330 (search-forward-regexp tramp-smb-errors nil t)
280 (tramp-error 331 (tramp-error
281 v 'file-error "%s `%s'" (match-string 0) directory))) 332 v 'file-error "%s `%s'" (match-string 0) directory)))
282 ;; Always go home 333 ;; Always go home.
283 (tramp-smb-send-command v (format "cd \\"))))))) 334 (tramp-smb-send-command v (format "cd \\")))))))
284 335
285 (defun tramp-smb-handle-delete-file (filename) 336 (defun tramp-smb-handle-delete-file (filename)
286 "Like `delete-file' for Tramp files." 337 "Like `delete-file' for Tramp files."
287 (setq filename (expand-file-name filename)) 338 (setq filename (expand-file-name filename))
295 (file (file-name-nondirectory localname))) 346 (file (file-name-nondirectory localname)))
296 (unwind-protect 347 (unwind-protect
297 (unless (and 348 (unless (and
298 (tramp-smb-send-command v (format "cd \"%s\"" dir)) 349 (tramp-smb-send-command v (format "cd \"%s\"" dir))
299 (tramp-smb-send-command v (format "rm \"%s\"" file))) 350 (tramp-smb-send-command v (format "rm \"%s\"" file)))
300 ;; Error 351 ;; Error.
301 (with-current-buffer (tramp-get-connection-buffer v) 352 (with-current-buffer (tramp-get-connection-buffer v)
302 (goto-char (point-min)) 353 (goto-char (point-min))
303 (search-forward-regexp tramp-smb-errors nil t) 354 (search-forward-regexp tramp-smb-errors nil t)
304 (tramp-error 355 (tramp-error
305 v 'file-error "%s `%s'" (match-string 0) filename))) 356 v 'file-error "%s `%s'" (match-string 0) filename)))
306 ;; Always go home 357 ;; Always go home.
307 (tramp-smb-send-command v (format "cd \\"))))))) 358 (tramp-smb-send-command v (format "cd \\")))))))
308 359
309 (defun tramp-smb-handle-directory-files 360 (defun tramp-smb-handle-directory-files
310 (directory &optional full match nosort) 361 (directory &optional full match nosort)
311 "Like `directory-files' for Tramp files." 362 "Like `directory-files' for Tramp files."
312 (let ((result (mapcar 'directory-file-name 363 (let ((result (mapcar 'directory-file-name
313 (file-name-all-completions "" directory)))) 364 (file-name-all-completions "" directory))))
314 ;; Discriminate with regexp 365 ;; Discriminate with regexp.
315 (when match 366 (when match
316 (setq result 367 (setq result
317 (delete nil 368 (delete nil
318 (mapcar (lambda (x) (when (string-match match x) x)) 369 (mapcar (lambda (x) (when (string-match match x) x))
319 result)))) 370 result))))
320 ;; Append directory 371 ;; Append directory.
321 (when full 372 (when full
322 (setq result 373 (setq result
323 (mapcar 374 (mapcar
324 (lambda (x) (expand-file-name x directory)) 375 (lambda (x) (expand-file-name x directory))
325 result))) 376 result)))
326 ;; Sort them if necessary 377 ;; Sort them if necessary.
327 (unless nosort (setq result (sort result 'string-lessp))) 378 (unless nosort (setq result (sort result 'string-lessp)))
328 ;; That's it 379 ;; That's it.
329 result)) 380 result))
330 381
331 (defun tramp-smb-handle-directory-files-and-attributes 382 (defun tramp-smb-handle-directory-files-and-attributes
332 (directory &optional full match nosort id-format) 383 (directory &optional full match nosort id-format)
333 "Like `directory-files-and-attributes' for Tramp files." 384 "Like `directory-files-and-attributes' for Tramp files."
334 (mapcar 385 (mapcar
335 (lambda (x) 386 (lambda (x)
336 (cons x (tramp-compat-file-attributes 387 (cons x (tramp-compat-file-attributes
337 (if full x (expand-file-name x directory)) id-format))) 388 (if full x (expand-file-name x directory)) id-format)))
338 (directory-files directory full match nosort))) 389 (directory-files directory full match nosort)))
390
391 (defun tramp-smb-handle-expand-file-name (name &optional dir)
392 "Like `expand-file-name' for Tramp files."
393 ;; If DIR is not given, use DEFAULT-DIRECTORY or "/".
394 (setq dir (or dir default-directory "/"))
395 ;; Unless NAME is absolute, concat DIR and NAME.
396 (unless (file-name-absolute-p name)
397 (setq name (concat (file-name-as-directory dir) name)))
398 ;; If NAME is not a Tramp file, run the real handler.
399 (if (not (tramp-tramp-file-p name))
400 (tramp-run-real-handler 'expand-file-name (list name nil))
401 ;; Dissect NAME.
402 (with-parsed-tramp-file-name name nil
403 (unless (tramp-run-real-handler 'file-name-absolute-p (list localname))
404 (setq localname (concat "/" localname)))
405 ;; Tilde expansion if necessary. We use the user name as share,
406 ;; which is offen the case in work groups.
407 (when (string-match "\\`~[^/]*" localname)
408 (setq localname
409 (replace-match
410 (if (zerop (length (match-string 0 localname)))
411 (tramp-file-name-real-user v)
412 (match-string 0 localname))
413 nil nil localname)))
414 ;; No tilde characters in file name, do normal
415 ;; `expand-file-name' (this does "/./" and "/../").
416 (tramp-make-tramp-file-name
417 method user host
418 (tramp-run-real-handler 'expand-file-name (list localname))))))
339 419
340 (defun tramp-smb-handle-file-attributes (filename &optional id-format) 420 (defun tramp-smb-handle-file-attributes (filename &optional id-format)
341 "Like `file-attributes' for Tramp files." 421 "Like `file-attributes' for Tramp files."
342 ;; Reading just the filename entry via "dir localname" is not 422 ;; Reading just the filename entry via "dir localname" is not
343 ;; possible, because when filename is a directory, some smbclient 423 ;; possible, because when filename is a directory, some smbclient
346 ;; retrieved, and the entry of the filename is extracted from. 426 ;; retrieved, and the entry of the filename is extracted from.
347 (with-parsed-tramp-file-name filename nil 427 (with-parsed-tramp-file-name filename nil
348 (with-file-property v localname (format "file-attributes-%s" id-format) 428 (with-file-property v localname (format "file-attributes-%s" id-format)
349 (let* ((entries (tramp-smb-get-file-entries 429 (let* ((entries (tramp-smb-get-file-entries
350 (file-name-directory filename))) 430 (file-name-directory filename)))
351 (entry (and entries 431 (entry (assoc (file-name-nondirectory filename) entries))
352 (assoc (file-name-nondirectory filename) entries)))
353 (uid (if (and id-format (equal id-format 'string)) "nobody" -1)) 432 (uid (if (and id-format (equal id-format 'string)) "nobody" -1))
354 (gid (if (and id-format (equal id-format 'string)) "nogroup" -1)) 433 (gid (if (and id-format (equal id-format 'string)) "nogroup" -1))
355 (inode (tramp-get-inode v)) 434 (inode (tramp-get-inode v))
356 (device (tramp-get-device v))) 435 (device (tramp-get-device v)))
357 436
440 (setq filename (expand-file-name filename)) 519 (setq filename (expand-file-name filename))
441 (when full-directory-p 520 (when full-directory-p
442 ;; Called from `dired-add-entry'. 521 ;; Called from `dired-add-entry'.
443 (setq filename (file-name-as-directory filename))) 522 (setq filename (file-name-as-directory filename)))
444 (with-parsed-tramp-file-name filename nil 523 (with-parsed-tramp-file-name filename nil
445 (tramp-flush-file-property v (file-name-directory localname))
446 (save-match-data 524 (save-match-data
447 (let ((base (file-name-nondirectory filename)) 525 (let ((base (file-name-nondirectory filename))
448 ;; We should not destroy the cache entry. 526 ;; We should not destroy the cache entry.
449 (entries (copy-sequence 527 (entries (copy-sequence
450 (tramp-smb-get-file-entries 528 (tramp-smb-get-file-entries
525 (setq dir (expand-file-name dir default-directory))) 603 (setq dir (expand-file-name dir default-directory)))
526 (with-parsed-tramp-file-name dir nil 604 (with-parsed-tramp-file-name dir nil
527 (save-match-data 605 (save-match-data
528 (let* ((share (tramp-smb-get-share localname)) 606 (let* ((share (tramp-smb-get-share localname))
529 (ldir (file-name-directory dir))) 607 (ldir (file-name-directory dir)))
530 ;; Make missing directory parts 608 ;; Make missing directory parts.
531 (when (and parents share (not (file-directory-p ldir))) 609 (when (and parents share (not (file-directory-p ldir)))
532 (make-directory ldir parents)) 610 (make-directory ldir parents))
533 ;; Just do it 611 ;; Just do it.
534 (when (file-directory-p ldir) 612 (when (file-directory-p ldir)
535 (make-directory-internal dir)) 613 (make-directory-internal dir))
536 (unless (file-directory-p dir) 614 (unless (file-directory-p dir)
537 (tramp-error v 'file-error "Couldn't make directory %s" dir)))))) 615 (tramp-error v 'file-error "Couldn't make directory %s" dir))))))
538 616
589 (tramp-message 667 (tramp-message
590 v 0 "Copying file %s to file %s...done" filename newname) 668 v 0 "Copying file %s to file %s...done" filename newname)
591 (tramp-error v 'file-error "Cannot rename `%s'" filename)))))) 669 (tramp-error v 'file-error "Cannot rename `%s'" filename))))))
592 670
593 (delete-file filename)) 671 (delete-file filename))
672
673 (defun tramp-smb-handle-set-file-modes (filename mode)
674 "Like `set-file-modes' for Tramp files."
675 (with-parsed-tramp-file-name filename nil
676 (tramp-flush-file-property v localname)
677 (unless (tramp-smb-send-command
678 v (format "chmod \"%s\" %s"
679 (tramp-smb-get-localname localname t)
680 (tramp-decimal-to-octal mode)))
681 (tramp-error
682 v 'file-error "Error while changing file's mode %s" filename))))
594 683
595 (defun tramp-smb-handle-substitute-in-file-name (filename) 684 (defun tramp-smb-handle-substitute-in-file-name (filename)
596 "Like `handle-substitute-in-file-name' for Tramp files. 685 "Like `handle-substitute-in-file-name' for Tramp files.
597 \"//\" substitutes only in the local filename part. Catches 686 \"//\" substitutes only in the local filename part. Catches
598 errors for shares like \"C$/\", which are common in Microsoft Windows." 687 errors for shares like \"C$/\", which are common in Microsoft Windows."
650 "Buffer has changed from `%s' to `%s'" curbuf (current-buffer))) 739 "Buffer has changed from `%s' to `%s'" curbuf (current-buffer)))
651 (when (eq visit t) 740 (when (eq visit t)
652 (set-visited-file-modtime))))) 741 (set-visited-file-modtime)))))
653 742
654 743
655 ;; Internal file name functions 744 ;; Internal file name functions.
656 745
657 (defun tramp-smb-get-share (localname) 746 (defun tramp-smb-get-share (localname)
658 "Returns the share name of LOCALNAME." 747 "Returns the share name of LOCALNAME."
659 (save-match-data 748 (save-match-data
660 (when (string-match "^/?\\([^/]+\\)/" localname) 749 (when (string-match "^/?\\([^/]+\\)/" localname)
675 (match-string 1 res)) 764 (match-string 1 res))
676 (if (string-match "^/?\\([^/]+\\)$" res) 765 (if (string-match "^/?\\([^/]+\\)$" res)
677 (match-string 1 res) 766 (match-string 1 res)
678 ""))) 767 "")))
679 768
680 ;; Sometimes we have discarded `substitute-in-file-name' 769 ;; Sometimes we have discarded `substitute-in-file-name'.
681 (when (string-match "\\(\\$\\$\\)\\(/\\|$\\)" res) 770 (when (string-match "\\(\\$\\$\\)\\(/\\|$\\)" res)
682 (setq res (replace-match "$" nil nil res 1))) 771 (setq res (replace-match "$" nil nil res 1)))
683 772
684 res))) 773 res)))
685 774
697 (file (tramp-smb-get-localname localname nil)) 786 (file (tramp-smb-get-localname localname nil))
698 (cache (tramp-get-connection-property v "share-cache" nil)) 787 (cache (tramp-get-connection-property v "share-cache" nil))
699 res entry) 788 res entry)
700 789
701 (if (and (not share) cache) 790 (if (and (not share) cache)
702 ;; Return cached shares 791 ;; Return cached shares.
703 (setq res cache) 792 (setq res cache)
704 793
705 ;; Read entries 794 ;; Read entries.
706 (setq file (file-name-as-directory file)) 795 (setq file (file-name-as-directory file))
707 (when (string-match "^\\./" file) 796 (when (string-match "^\\./" file)
708 (setq file (substring file 1))) 797 (setq file (substring file 1)))
709 (if share 798 (if share
710 (tramp-smb-send-command v (format "dir \"%s*\"" file)) 799 (tramp-smb-send-command v (format "dir \"%s*\"" file))
711 ;; `tramp-smb-maybe-open-connection' lists also the share names 800 ;; `tramp-smb-maybe-open-connection' lists also the share names.
712 (tramp-smb-maybe-open-connection v)) 801 (tramp-smb-maybe-open-connection v))
713 802
714 ;; Loop the listing 803 ;; Loop the listing.
715 (goto-char (point-min)) 804 (goto-char (point-min))
716 (unless (re-search-forward tramp-smb-errors nil t) 805 (unless (re-search-forward tramp-smb-errors nil t)
717 (while (not (eobp)) 806 (while (not (eobp))
718 (setq entry (tramp-smb-read-file-entry share)) 807 (setq entry (tramp-smb-read-file-entry share))
719 (forward-line) 808 (forward-line)
720 (when entry (add-to-list 'res entry)))) 809 (when entry (add-to-list 'res entry))))
721 810
722 ;; Cache share entries 811 ;; Cache share entries.
723 (unless share 812 (unless share
724 (tramp-set-connection-property v "share-cache" res))) 813 (tramp-set-connection-property v "share-cache" res)))
725 814
726 ;; Add directory itself 815 ;; Add directory itself.
727 (add-to-list 'res '("" "drwxrwxrwx" 0 (0 0))) 816 (add-to-list 'res '("" "drwxrwxrwx" 0 (0 0)))
728 817
729 ;; There's a very strange error (debugged with XEmacs 21.4.14) 818 ;; There's a very strange error (debugged with XEmacs 21.4.14)
730 ;; If there's no short delay, it returns nil. No idea about. 819 ;; If there's no short delay, it returns nil. No idea about.
731 (when (featurep 'xemacs) (sleep-for 0.01)) 820 (when (featurep 'xemacs) (sleep-for 0.01))
732 821
733 ;; Return entries 822 ;; Return entries.
734 (delq nil res)))))) 823 (delq nil res))))))
735 824
736 ;; Return either a share name (if SHARE is nil), or a file name 825 ;; Return either a share name (if SHARE is nil), or a file name.
737 ;; 826 ;;
738 ;; If shares are listed, the following format is expected 827 ;; If shares are listed, the following format is expected:
739 ;; 828 ;;
740 ;; \s-\{8,8} - leading spaces 829 ;; \s-\{8,8} - leading spaces
741 ;; \S-\(.*\S-\)\s-* - share name, 14 char 830 ;; \S-\(.*\S-\)\s-* - share name, 14 char
742 ;; \s- - space delimeter 831 ;; \s- - space delimeter
743 ;; \S-+\s-* - type, 8 char, "Disk " expected 832 ;; \S-+\s-* - type, 8 char, "Disk " expected
805 size 0)) 894 size 0))
806 895
807 ;; Real listing. 896 ;; Real listing.
808 (block nil 897 (block nil
809 898
810 ;; year 899 ;; year.
811 (if (string-match "\\([0-9]+\\)$" line) 900 (if (string-match "\\([0-9]+\\)$" line)
812 (setq year (string-to-number (match-string 1 line)) 901 (setq year (string-to-number (match-string 1 line))
813 line (substring line 0 -5)) 902 line (substring line 0 -5))
814 (return)) 903 (return))
815 904
816 ;; time 905 ;; time.
817 (if (string-match "\\([0-9]+\\):\\([0-9]+\\):\\([0-9]+\\)$" line) 906 (if (string-match "\\([0-9]+\\):\\([0-9]+\\):\\([0-9]+\\)$" line)
818 (setq hour (string-to-number (match-string 1 line)) 907 (setq hour (string-to-number (match-string 1 line))
819 min (string-to-number (match-string 2 line)) 908 min (string-to-number (match-string 2 line))
820 sec (string-to-number (match-string 3 line)) 909 sec (string-to-number (match-string 3 line))
821 line (substring line 0 -9)) 910 line (substring line 0 -9))
822 (return)) 911 (return))
823 912
824 ;; day 913 ;; day.
825 (if (string-match "\\([0-9]+\\)$" line) 914 (if (string-match "\\([0-9]+\\)$" line)
826 (setq day (string-to-number (match-string 1 line)) 915 (setq day (string-to-number (match-string 1 line))
827 line (substring line 0 -3)) 916 line (substring line 0 -3))
828 (return)) 917 (return))
829 918
830 ;; month 919 ;; month.
831 (if (string-match "\\(\\w+\\)$" line) 920 (if (string-match "\\(\\w+\\)$" line)
832 (setq month (match-string 1 line) 921 (setq month (match-string 1 line)
833 line (substring line 0 -4)) 922 line (substring line 0 -4))
834 (return)) 923 (return))
835 924
836 ;; weekday 925 ;; weekday.
837 (if (string-match "\\(\\w+\\)$" line) 926 (if (string-match "\\(\\w+\\)$" line)
838 (setq line (substring line 0 -5)) 927 (setq line (substring line 0 -5))
839 (return)) 928 (return))
840 929
841 ;; size 930 ;; size.
842 (if (string-match "\\([0-9]+\\)$" line) 931 (if (string-match "\\([0-9]+\\)$" line)
843 (let ((length (- (max 10 (1+ (length (match-string 1 line))))))) 932 (let ((length (- (max 10 (1+ (length (match-string 1 line)))))))
844 (setq size (string-to-number (match-string 1 line))) 933 (setq size (string-to-number (match-string 1 line)))
845 (when (string-match "\\([ADHRSV]+\\)" (substring line length)) 934 (when (string-match "\\([ADHRSV]+\\)" (substring line length))
846 (setq length (+ length (match-end 0)))) 935 (setq length (+ length (match-end 0))))
847 (setq line (substring line 0 length))) 936 (setq line (substring line 0 length)))
848 (return)) 937 (return))
849 938
850 ;; mode: ARCH, DIR, HIDDEN, RONLY, SYSTEM, VOLID 939 ;; mode: ARCH, DIR, HIDDEN, RONLY, SYSTEM, VOLID.
851 (if (string-match "\\([ADHRSV]+\\)?$" line) 940 (if (string-match "\\([ADHRSV]+\\)?$" line)
852 (setq 941 (setq
853 mode (or (match-string 1 line) "") 942 mode (or (match-string 1 line) "")
854 mode (save-match-data (format 943 mode (save-match-data (format
855 "%s%s" 944 "%s%s"
858 (lambda (x) "") " " 947 (lambda (x) "") " "
859 (concat "r" (if (string-match "R" mode) "-" "w") "x")))) 948 (concat "r" (if (string-match "R" mode) "-" "w") "x"))))
860 line (substring line 0 -7)) 949 line (substring line 0 -7))
861 (return)) 950 (return))
862 951
863 ;; localname 952 ;; localname.
864 (if (string-match "^\\s-+\\(\\S-\\(.*\\S-\\)?\\)\\s-*$" line) 953 (if (string-match "^\\s-+\\(\\S-\\(.*\\S-\\)?\\)\\s-*$" line)
865 (setq localname (match-string 1 line)) 954 (setq localname (match-string 1 line))
866 (return)))) 955 (return))))
867 956
868 (when (and localname mode size) 957 (when (and localname mode size)
874 year) 963 year)
875 '(0 0))) 964 '(0 0)))
876 (list localname mode size mtime)))) 965 (list localname mode size mtime))))
877 966
878 967
879 ;; Connection functions 968 ;; Connection functions.
880 969
881 (defun tramp-smb-send-command (vec command) 970 (defun tramp-smb-send-command (vec command)
882 "Send the COMMAND to connection VEC. 971 "Send the COMMAND to connection VEC.
883 Returns nil if there has been an error message from smbclient." 972 Returns nil if there has been an error message from smbclient."
884 (tramp-smb-maybe-open-connection vec) 973 (tramp-smb-maybe-open-connection vec)
892 connection if a previous connection has died for some reason." 981 connection if a previous connection has died for some reason."
893 (let* ((share (tramp-smb-get-share (tramp-file-name-localname vec))) 982 (let* ((share (tramp-smb-get-share (tramp-file-name-localname vec)))
894 (buf (tramp-get-buffer vec)) 983 (buf (tramp-get-buffer vec))
895 (p (get-buffer-process buf))) 984 (p (get-buffer-process buf)))
896 985
986 ;; Check whether we still have the same smbclient version.
987 ;; Otherwise, we must delete the connection cache, because
988 ;; capabilities migh have changed.
989 (unless (processp p)
990 (unless (let ((default-directory
991 (tramp-compat-temporary-file-directory)))
992 (executable-find tramp-smb-program))
993 (tramp-error
994 vec 'file-error
995 "Cannot find command %s in %s" tramp-smb-program exec-path))
996
997 (let* ((default-directory (tramp-compat-temporary-file-directory))
998 (smbclient-version
999 (shell-command-to-string (concat tramp-smb-program " -V"))))
1000 (unless (string-equal
1001 smbclient-version
1002 (tramp-get-connection-property vec "smbclient-version" ""))
1003 (tramp-flush-directory-property vec "")
1004 (tramp-flush-connection-property vec)
1005 (tramp-set-connection-property
1006 vec "smbclient-version" smbclient-version)
1007 (setq buf (tramp-get-buffer vec)))))
1008
897 ;; If too much time has passed since last command was sent, look 1009 ;; If too much time has passed since last command was sent, look
898 ;; whether has been an error message; maybe due to connection timeout. 1010 ;; whether there has been an error message; maybe due to
1011 ;; connection timeout.
899 (with-current-buffer buf 1012 (with-current-buffer buf
900 (goto-char (point-min)) 1013 (goto-char (point-min))
901 (when (and (> (tramp-time-diff 1014 (when (and (> (tramp-time-diff
902 (current-time) 1015 (current-time)
903 (tramp-get-connection-property 1016 (tramp-get-connection-property
918 (save-match-data 1031 (save-match-data
919 ;; There might be unread output from checking for share names. 1032 ;; There might be unread output from checking for share names.
920 (when buf (with-current-buffer buf (erase-buffer))) 1033 (when buf (with-current-buffer buf (erase-buffer)))
921 (when (and p (processp p)) (delete-process p)) 1034 (when (and p (processp p)) (delete-process p))
922 1035
923 (unless (let ((default-directory
924 (tramp-compat-temporary-file-directory)))
925 (executable-find tramp-smb-program))
926 (error "Cannot find command %s in %s" tramp-smb-program exec-path))
927
928 (let* ((user (tramp-file-name-user vec)) 1036 (let* ((user (tramp-file-name-user vec))
929 (host (tramp-file-name-host vec)) 1037 (host (tramp-file-name-host vec))
930 (real-user (tramp-file-name-real-user vec)) 1038 (real-user (tramp-file-name-real-user vec))
931 (real-host (tramp-file-name-real-host vec)) 1039 (real-host (tramp-file-name-real-host vec))
932 (domain (tramp-file-name-domain vec)) 1040 (domain (tramp-file-name-domain vec))
960 tramp-smb-program args)))) 1068 tramp-smb-program args))))
961 1069
962 (tramp-message 1070 (tramp-message
963 vec 6 "%s" (mapconcat 'identity (process-command p) " ")) 1071 vec 6 "%s" (mapconcat 'identity (process-command p) " "))
964 (tramp-set-process-query-on-exit-flag p nil) 1072 (tramp-set-process-query-on-exit-flag p nil)
965 (tramp-set-connection-property p "smb-share" share)
966 1073
967 ;; Set variables for computing the prompt for reading password. 1074 ;; Set variables for computing the prompt for reading password.
968 (setq tramp-current-method tramp-smb-method 1075 (setq tramp-current-method tramp-smb-method
969 tramp-current-user user 1076 tramp-current-user user
970 tramp-current-host host) 1077 tramp-current-host host)
971
972 ;; Set chunksize. Otherwise, `tramp-send-string' might
973 ;; try it itself.
974 (tramp-set-connection-property p "chunksize" tramp-chunksize)
975 1078
976 ;; Play login scenario. 1079 ;; Play login scenario.
977 (tramp-process-actions 1080 (tramp-process-actions
978 p vec 1081 p vec
979 (if share 1082 (if share
980 tramp-smb-actions-with-share 1083 tramp-smb-actions-with-share
981 tramp-smb-actions-without-share)) 1084 tramp-smb-actions-without-share))
1085
1086 ;; Check server version.
1087 (with-current-buffer (tramp-get-connection-buffer vec)
1088 (goto-char (point-min))
1089 (search-forward-regexp
1090 "Domain=\\[[^]]*\\] OS=\\[[^]]*\\] Server=\\[[^]]*\\]" nil t)
1091 (let ((smbserver-version (match-string 0)))
1092 (when (not (string-equal
1093 smbserver-version
1094 (tramp-get-connection-property
1095 vec "smbserver-version" "")))
1096 (tramp-flush-directory-property vec "")
1097 (tramp-flush-connection-property vec)
1098 (tramp-set-connection-property
1099 vec "smbserver-version" smbserver-version))))
1100
1101 ;; Set chunksize. Otherwise, `tramp-send-string' might
1102 ;; try it itself.
1103 (tramp-set-connection-property p "smb-share" share)
1104 (tramp-set-connection-property p "chunksize" tramp-chunksize)
982 1105
983 (tramp-message 1106 (tramp-message
984 vec 3 "Opening connection for //%s%s/%s...done" 1107 vec 3 "Opening connection for //%s%s/%s...done"
985 (if (not (zerop (length user))) (concat user "@") "") 1108 (if (not (zerop (length user))) (concat user "@") "")
986 host (or share "")))))))) 1109 host (or share ""))))))))
1031 1154
1032 ;;; TODO: 1155 ;;; TODO:
1033 1156
1034 ;; * Error handling in case password is wrong. 1157 ;; * Error handling in case password is wrong.
1035 ;; * Read password from "~/.netrc". 1158 ;; * Read password from "~/.netrc".
1036 ;; * Return more comprehensive file permission string. Think whether it is 1159 ;; * Return more comprehensive file permission string.
1037 ;; possible to implement `set-file-modes'.
1038 ;; * Handle links (FILENAME.LNK). 1160 ;; * Handle links (FILENAME.LNK).
1039 ;; * Try to remove the inclusion of dummy "" directory. Seems to be at 1161 ;; * Try to remove the inclusion of dummy "" directory. Seems to be at
1040 ;; several places, especially in `tramp-smb-handle-insert-directory'. 1162 ;; several places, especially in `tramp-smb-handle-insert-directory'.
1041 ;; * (RMS) Use unwind-protect to clean up the state so as to make the state 1163 ;; * (RMS) Use unwind-protect to clean up the state so as to make the state
1042 ;; regular again. 1164 ;; regular again.