Mercurial > emacs
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. |