Mercurial > emacs
comparison lisp/net/tramp-smb.el @ 105551:2025d7d04cb9
* net/tramp-smb.el (tramp-smb-errors): Add error messages.
(tramp-smb-file-name-handler-alist): Add handlers for
`add-name-to-file', `make-symbolic-link'.
(tramp-smb-handle-add-name-to-file)
(tramp-do-file-attributes-with-stat)
(tramp-smb-handle-make-symbolic-link)
(tramp-smb-get-cifs-capabilities): New defuns.
(tramp-smb-handle-copy-directory, tramp-smb-handle-copy-file)
(tramp-smb-handle-delete-directory, tramp-smb-handle-delete-file)
(tramp-smb-handle-file-local-copy)
(tramp-smb-handle-make-directory-internal)
(tramp-smb-handle-rename-file, tramp-smb-handle-write-region): The
file name syntax depends on cifs capabilities.
(tramp-smb-handle-file-attributes); Call
`tramp-do-file-attributes-with-stat' if possible.
(tramp-smb-handle-insert-directory): Use posix attributes if
possible.
(tramp-smb-handle-set-file-modes): It is applicable for posix
only.
author | Michael Albinus <michael.albinus@gmx.de> |
---|---|
date | Sun, 11 Oct 2009 14:01:43 +0000 |
parents | e781cac84553 |
children | 59dc4314dfa4 |
comparison
equal
deleted
inserted
replaced
105550:42674c5ffbe7 | 105551:2025d7d04cb9 |
---|---|
93 "NT_STATUS_DIRECTORY_NOT_EMPTY" | 93 "NT_STATUS_DIRECTORY_NOT_EMPTY" |
94 "NT_STATUS_DUPLICATE_NAME" | 94 "NT_STATUS_DUPLICATE_NAME" |
95 "NT_STATUS_FILE_IS_A_DIRECTORY" | 95 "NT_STATUS_FILE_IS_A_DIRECTORY" |
96 "NT_STATUS_LOGON_FAILURE" | 96 "NT_STATUS_LOGON_FAILURE" |
97 "NT_STATUS_NETWORK_ACCESS_DENIED" | 97 "NT_STATUS_NETWORK_ACCESS_DENIED" |
98 "NT_STATUS_NOT_IMPLEMENTED" | |
98 "NT_STATUS_NO_SUCH_FILE" | 99 "NT_STATUS_NO_SUCH_FILE" |
99 "NT_STATUS_OBJECT_NAME_COLLISION" | 100 "NT_STATUS_OBJECT_NAME_COLLISION" |
100 "NT_STATUS_OBJECT_NAME_INVALID" | 101 "NT_STATUS_OBJECT_NAME_INVALID" |
101 "NT_STATUS_OBJECT_NAME_NOT_FOUND" | 102 "NT_STATUS_OBJECT_NAME_NOT_FOUND" |
102 "NT_STATUS_SHARING_VIOLATION" | 103 "NT_STATUS_SHARING_VIOLATION" |
129 | 130 |
130 ;; New handlers should be added here. | 131 ;; New handlers should be added here. |
131 (defconst tramp-smb-file-name-handler-alist | 132 (defconst tramp-smb-file-name-handler-alist |
132 '( | 133 '( |
133 ;; `access-file' performed by default handler. | 134 ;; `access-file' performed by default handler. |
134 (add-name-to-file . tramp-smb-handle-copy-file) ;; we're on Windows, honey. | 135 (add-name-to-file . tramp-smb-handle-add-name-to-file) |
135 ;; `byte-compiler-base-file-name' performed by default handler. | 136 ;; `byte-compiler-base-file-name' performed by default handler. |
136 (copy-directory . tramp-smb-handle-copy-directory) | 137 (copy-directory . tramp-smb-handle-copy-directory) |
137 (copy-file . tramp-smb-handle-copy-file) | 138 (copy-file . tramp-smb-handle-copy-file) |
138 (delete-directory . tramp-smb-handle-delete-directory) | 139 (delete-directory . tramp-smb-handle-delete-directory) |
139 (delete-file . tramp-smb-handle-delete-file) | 140 (delete-file . tramp-smb-handle-delete-file) |
173 (insert-directory . tramp-smb-handle-insert-directory) | 174 (insert-directory . tramp-smb-handle-insert-directory) |
174 (insert-file-contents . tramp-handle-insert-file-contents) | 175 (insert-file-contents . tramp-handle-insert-file-contents) |
175 (load . tramp-handle-load) | 176 (load . tramp-handle-load) |
176 (make-directory . tramp-smb-handle-make-directory) | 177 (make-directory . tramp-smb-handle-make-directory) |
177 (make-directory-internal . tramp-smb-handle-make-directory-internal) | 178 (make-directory-internal . tramp-smb-handle-make-directory-internal) |
178 (make-symbolic-link . ignore) | 179 (make-symbolic-link . tramp-smb-handle-make-symbolic-link) |
179 (rename-file . tramp-smb-handle-rename-file) | 180 (rename-file . tramp-smb-handle-rename-file) |
180 (set-file-modes . tramp-smb-handle-set-file-modes) | 181 (set-file-modes . tramp-smb-handle-set-file-modes) |
181 (set-file-times . ignore) | 182 (set-file-times . ignore) |
182 (set-visited-file-modtime . ignore) | 183 (set-visited-file-modtime . ignore) |
183 (shell-command . ignore) | 184 (shell-command . ignore) |
207 (add-to-list 'tramp-foreign-file-name-handler-alist | 208 (add-to-list 'tramp-foreign-file-name-handler-alist |
208 (cons 'tramp-smb-file-name-p 'tramp-smb-file-name-handler)) | 209 (cons 'tramp-smb-file-name-p 'tramp-smb-file-name-handler)) |
209 | 210 |
210 | 211 |
211 ;; File name primitives. | 212 ;; File name primitives. |
213 | |
214 (defun tramp-smb-handle-add-name-to-file | |
215 (filename newname &optional ok-if-already-exists) | |
216 "Like `add-name-to-file' for Tramp files." | |
217 (unless (tramp-equal-remote filename newname) | |
218 (with-parsed-tramp-file-name | |
219 (if (tramp-tramp-file-p filename) filename newname) nil | |
220 (tramp-error | |
221 v 'file-error | |
222 "add-name-to-file: %s" | |
223 "only implemented for same method, same user, same host"))) | |
224 (with-parsed-tramp-file-name filename v1 | |
225 (with-parsed-tramp-file-name newname v2 | |
226 (when (file-directory-p filename) | |
227 (tramp-error | |
228 v2 'file-error | |
229 "add-name-to-file: %s must not be a directory" filename)) | |
230 (when (and (not ok-if-already-exists) | |
231 (file-exists-p newname) | |
232 (not (numberp ok-if-already-exists)) | |
233 (y-or-n-p | |
234 (format | |
235 "File %s already exists; make it a new name anyway? " | |
236 newname))) | |
237 (tramp-error | |
238 v2 'file-error | |
239 "add-name-to-file: file %s already exists" newname)) | |
240 ;; We must also flush the cache of the directory, because | |
241 ;; `file-attributes' reads the values from there. | |
242 (tramp-flush-file-property v2 (file-name-directory v2-localname)) | |
243 (tramp-flush-file-property v2 v2-localname) | |
244 (let ((cifs (tramp-smb-get-cifs-capabilities v1))) | |
245 (unless | |
246 (tramp-smb-send-command | |
247 v1 | |
248 (format | |
249 "%s \"%s\" \"%s\"" | |
250 (if cifs "link" "hardlink") | |
251 (tramp-smb-get-localname v1-localname (not cifs)) | |
252 (tramp-smb-get-localname v2-localname (not cifs)))) | |
253 (tramp-error | |
254 v2 'file-error | |
255 "error with add-name-to-file, see buffer `%s' for details" | |
256 (buffer-name))))))) | |
212 | 257 |
213 (defun tramp-smb-handle-copy-directory | 258 (defun tramp-smb-handle-copy-directory |
214 (dirname newname &optional keep-date parents) | 259 (dirname newname &optional keep-date parents) |
215 "Like `copy-directory' for Tramp files." | 260 "Like `copy-directory' for Tramp files." |
216 (setq dirname (expand-file-name dirname) | 261 (setq dirname (expand-file-name dirname) |
232 (copy-directory tmpdir newname keep-date parents)) | 277 (copy-directory tmpdir newname keep-date parents)) |
233 (delete-directory tmpdir 'recursive)))) | 278 (delete-directory tmpdir 'recursive)))) |
234 ((or t1 t2) | 279 ((or t1 t2) |
235 ;; We can copy recursively. | 280 ;; We can copy recursively. |
236 (let ((prompt (tramp-smb-send-command v "prompt")) | 281 (let ((prompt (tramp-smb-send-command v "prompt")) |
237 (recurse (tramp-smb-send-command v "recurse"))) | 282 (recurse (tramp-smb-send-command v "recurse")) |
283 (cifs (tramp-smb-get-cifs-capabilities v))) | |
238 (unless (file-directory-p newname) | 284 (unless (file-directory-p newname) |
239 (make-directory newname parents)) | 285 (make-directory newname parents)) |
240 (unwind-protect | 286 (unwind-protect |
241 (unless | 287 (unless |
242 (and | 288 (and |
243 prompt recurse | 289 prompt recurse |
244 (tramp-smb-send-command | 290 (tramp-smb-send-command |
245 v (format "cd \"%s\"" | 291 v (format |
246 (tramp-smb-get-localname localname t))) | 292 "cd \"%s\"" |
293 (tramp-smb-get-localname localname (not cifs)))) | |
247 (tramp-smb-send-command | 294 (tramp-smb-send-command |
248 v (format "lcd \"%s\"" (if t1 newname dirname))) | 295 v (format "lcd \"%s\"" (if t1 newname dirname))) |
249 (if t1 | 296 (if t1 |
250 (tramp-smb-send-command v "mget *") | 297 (tramp-smb-send-command v "mget *") |
251 (tramp-smb-send-command v "mput *"))) | 298 (tramp-smb-send-command v "mput *"))) |
254 (goto-char (point-min)) | 301 (goto-char (point-min)) |
255 (search-forward-regexp tramp-smb-errors nil t) | 302 (search-forward-regexp tramp-smb-errors nil t) |
256 (tramp-error | 303 (tramp-error |
257 v 'file-error | 304 v 'file-error |
258 "%s `%s'" (match-string 0) (if t1 dirname newname)))) | 305 "%s `%s'" (match-string 0) (if t1 dirname newname)))) |
259 ;; Always go home. | 306 ;; Go home. |
260 (tramp-smb-send-command v (format "cd \\")) | 307 (tramp-smb-send-command v (format "cd %s" (if cifs "/" "\\"))) |
261 ;; Toggle prompt and recurse OFF. | 308 ;; Toggle prompt and recurse OFF. |
262 (if prompt (tramp-smb-send-command v "prompt")) | 309 (if prompt (tramp-smb-send-command v "prompt")) |
263 (if recurse (tramp-smb-send-command v "recurse"))))) | 310 (if recurse (tramp-smb-send-command v "recurse"))))) |
264 (t | 311 (t |
265 ;; We must do it file-wise. | 312 ;; We must do it file-wise. |
293 (when (and (not ok-if-already-exists) | 340 (when (and (not ok-if-already-exists) |
294 (file-exists-p newname)) | 341 (file-exists-p newname)) |
295 (tramp-error v 'file-already-exists newname)) | 342 (tramp-error v 'file-already-exists newname)) |
296 | 343 |
297 ;; We must also flush the cache of the directory, because | 344 ;; We must also flush the cache of the directory, because |
298 ;; file-attributes reads the values from there. | 345 ;; `file-attributes' reads the values from there. |
299 (tramp-flush-file-property v (file-name-directory localname)) | 346 (tramp-flush-file-property v (file-name-directory localname)) |
300 (tramp-flush-file-property v localname) | 347 (tramp-flush-file-property v localname) |
301 (let ((share (tramp-smb-get-share localname)) | 348 (let ((share (tramp-smb-get-share localname)) |
302 (file (tramp-smb-get-localname localname t))) | 349 (file (tramp-smb-get-localname |
350 localname (not (tramp-smb-get-cifs-capabilities v))))) | |
303 (unless share | 351 (unless share |
304 (tramp-error | 352 (tramp-error |
305 v 'file-error "Target `%s' must contain a share name" newname)) | 353 v 'file-error "Target `%s' must contain a share name" newname)) |
306 (tramp-message v 0 "Copying file %s to file %s..." filename newname) | 354 (tramp-message v 0 "Copying file %s to file %s..." filename newname) |
307 (if (tramp-smb-send-command | 355 (if (tramp-smb-send-command |
326 ;; We do not want to delete "." and "..". | 374 ;; We do not want to delete "." and "..". |
327 (directory-files | 375 (directory-files |
328 directory 'full "^\\([^.]\\|\\.\\([^.]\\|\\..\\)\\).*"))) | 376 directory 'full "^\\([^.]\\|\\.\\([^.]\\|\\..\\)\\).*"))) |
329 (with-parsed-tramp-file-name directory nil | 377 (with-parsed-tramp-file-name directory nil |
330 ;; We must also flush the cache of the directory, because | 378 ;; We must also flush the cache of the directory, because |
331 ;; file-attributes reads the values from there. | 379 ;; `file-attributes' reads the values from there. |
332 (tramp-flush-file-property v (file-name-directory localname)) | 380 (tramp-flush-file-property v (file-name-directory localname)) |
333 (tramp-flush-directory-property v localname) | 381 (tramp-flush-directory-property v localname) |
334 (let ((dir (tramp-smb-get-localname (file-name-directory localname) t)) | 382 (let ((cifs (tramp-smb-get-cifs-capabilities v))) |
335 (file (file-name-nondirectory localname))) | 383 (unless (tramp-smb-send-command |
336 (unwind-protect | 384 v (format |
337 (unless (and | 385 "%s \"%s\"" |
338 (tramp-smb-send-command v (format "cd \"%s\"" dir)) | 386 (if cifs "posix_rmdir" "rmdir") |
339 (tramp-smb-send-command v (format "rmdir \"%s\"" file))) | 387 (tramp-smb-get-localname localname (not cifs)))) |
340 ;; Error. | 388 ;; Error. |
341 (with-current-buffer (tramp-get-connection-buffer v) | 389 (with-current-buffer (tramp-get-connection-buffer v) |
342 (goto-char (point-min)) | 390 (goto-char (point-min)) |
343 (search-forward-regexp tramp-smb-errors nil t) | 391 (search-forward-regexp tramp-smb-errors nil t) |
344 (tramp-error | 392 (tramp-error |
345 v 'file-error "%s `%s'" (match-string 0) directory))) | 393 v 'file-error "%s `%s'" (match-string 0) directory))))))) |
346 ;; Always go home. | |
347 (tramp-smb-send-command v (format "cd \\"))))))) | |
348 | 394 |
349 (defun tramp-smb-handle-delete-file (filename) | 395 (defun tramp-smb-handle-delete-file (filename) |
350 "Like `delete-file' for Tramp files." | 396 "Like `delete-file' for Tramp files." |
351 (setq filename (expand-file-name filename)) | 397 (setq filename (expand-file-name filename)) |
352 (when (file-exists-p filename) | 398 (when (file-exists-p filename) |
353 (with-parsed-tramp-file-name filename nil | 399 (with-parsed-tramp-file-name filename nil |
354 ;; We must also flush the cache of the directory, because | 400 ;; We must also flush the cache of the directory, because |
355 ;; file-attributes reads the values from there. | 401 ;; `file-attributes' reads the values from there. |
356 (tramp-flush-file-property v (file-name-directory localname)) | 402 (tramp-flush-file-property v (file-name-directory localname)) |
357 (tramp-flush-file-property v localname) | 403 (tramp-flush-file-property v localname) |
358 (let ((dir (tramp-smb-get-localname (file-name-directory localname) t)) | 404 (let ((cifs (tramp-smb-get-cifs-capabilities v))) |
359 (file (file-name-nondirectory localname))) | 405 (unless (tramp-smb-send-command |
360 (unwind-protect | 406 v (format |
361 (unless (and | 407 "%s \"%s\"" |
362 (tramp-smb-send-command v (format "cd \"%s\"" dir)) | 408 (if cifs "posix_unlink" "rm") |
363 (tramp-smb-send-command v (format "rm \"%s\"" file))) | 409 (tramp-smb-get-localname localname (not cifs)))) |
364 ;; Error. | 410 ;; Error. |
365 (with-current-buffer (tramp-get-connection-buffer v) | 411 (with-current-buffer (tramp-get-connection-buffer v) |
366 (goto-char (point-min)) | 412 (goto-char (point-min)) |
367 (search-forward-regexp tramp-smb-errors nil t) | 413 (search-forward-regexp tramp-smb-errors nil t) |
368 (tramp-error | 414 (tramp-error |
369 v 'file-error "%s `%s'" (match-string 0) filename))) | 415 v 'file-error "%s `%s'" (match-string 0) filename))))))) |
370 ;; Always go home. | |
371 (tramp-smb-send-command v (format "cd \\"))))))) | |
372 | 416 |
373 (defun tramp-smb-handle-directory-files | 417 (defun tramp-smb-handle-directory-files |
374 (directory &optional full match nosort) | 418 (directory &optional full match nosort) |
375 "Like `directory-files' for Tramp files." | 419 "Like `directory-files' for Tramp files." |
376 (let ((result (mapcar 'directory-file-name | 420 (let ((result (mapcar 'directory-file-name |
431 method user host | 475 method user host |
432 (tramp-run-real-handler 'expand-file-name (list localname)))))) | 476 (tramp-run-real-handler 'expand-file-name (list localname)))))) |
433 | 477 |
434 (defun tramp-smb-handle-file-attributes (filename &optional id-format) | 478 (defun tramp-smb-handle-file-attributes (filename &optional id-format) |
435 "Like `file-attributes' for Tramp files." | 479 "Like `file-attributes' for Tramp files." |
436 ;; Reading just the filename entry via "dir localname" is not | 480 (unless id-format (setq id-format 'integer)) |
437 ;; possible, because when filename is a directory, some smbclient | |
438 ;; versions return the content of the directory, and other versions | |
439 ;; don't. Therefore, the whole content of the upper directory is | |
440 ;; retrieved, and the entry of the filename is extracted from. | |
441 (with-parsed-tramp-file-name filename nil | 481 (with-parsed-tramp-file-name filename nil |
442 (with-file-property v localname (format "file-attributes-%s" id-format) | 482 (with-file-property v localname (format "file-attributes-%s" id-format) |
443 (let* ((entries (tramp-smb-get-file-entries | 483 (if (and (tramp-smb-get-share localname) |
444 (file-name-directory filename))) | 484 (tramp-smb-get-cifs-capabilities v)) |
445 (entry (assoc (file-name-nondirectory filename) entries)) | 485 (tramp-do-file-attributes-with-stat v localname id-format) |
446 (uid (if (and id-format (equal id-format 'string)) "nobody" -1)) | 486 ;; Reading just the filename entry via "dir localname" is not |
447 (gid (if (and id-format (equal id-format 'string)) "nogroup" -1)) | 487 ;; possible, because when filename is a directory, some |
448 (inode (tramp-get-inode v)) | 488 ;; smbclient versions return the content of the directory, and |
449 (device (tramp-get-device v))) | 489 ;; other versions don't. Therefore, the whole content of the |
450 | 490 ;; upper directory is retrieved, and the entry of the filename |
451 ;; Check result. | 491 ;; is extracted from. |
452 (when entry | 492 (let* ((entries (tramp-smb-get-file-entries |
453 (list (and (string-match "d" (nth 1 entry)) | 493 (file-name-directory filename))) |
454 t) ;0 file type | 494 (entry (assoc (file-name-nondirectory filename) entries)) |
455 -1 ;1 link count | 495 (uid (if (equal id-format 'string) "nobody" -1)) |
456 uid ;2 uid | 496 (gid (if (equal id-format 'string) "nogroup" -1)) |
457 gid ;3 gid | 497 (inode (tramp-get-inode v)) |
458 '(0 0) ;4 atime | 498 (device (tramp-get-device v))) |
459 (nth 3 entry) ;5 mtime | 499 |
460 '(0 0) ;6 ctime | 500 ;; Check result. |
461 (nth 2 entry) ;7 size | 501 (when entry |
462 (nth 1 entry) ;8 mode | 502 (list (and (string-match "d" (nth 1 entry)) |
463 nil ;9 gid weird | 503 t) ;0 file type |
464 inode ;10 inode number | 504 -1 ;1 link count |
465 device)))))) ;11 file system number | 505 uid ;2 uid |
506 gid ;3 gid | |
507 '(0 0) ;4 atime | |
508 (nth 3 entry) ;5 mtime | |
509 '(0 0) ;6 ctime | |
510 (nth 2 entry) ;7 size | |
511 (nth 1 entry) ;8 mode | |
512 nil ;9 gid weird | |
513 inode ;10 inode number | |
514 device))))))) ;11 file system number | |
515 | |
516 (defun tramp-do-file-attributes-with-stat | |
517 (vec localname &optional id-format) | |
518 "Implement `file-attributes' for Tramp files using stat command." | |
519 (tramp-message vec 5 "file attributes with stat: %s" localname) | |
520 (with-current-buffer (tramp-get-buffer vec) | |
521 (let* ((file (tramp-smb-get-localname localname nil)) | |
522 id link uid gid atime mtime ctime mode inode) | |
523 (tramp-smb-send-command vec (format "stat \"%s\"" file)) | |
524 | |
525 ;; Loop the listing. | |
526 (goto-char (point-min)) | |
527 (unless (re-search-forward tramp-smb-errors nil t) | |
528 (while (not (eobp)) | |
529 (cond | |
530 ;;File: /dbus | |
531 ((looking-at | |
532 "Size:\\s-+\\([0-9]+\\)\\s-+Blocks:\\s-+[0-9]+\\s-+\\(\\w+\\)") | |
533 (setq size (string-to-number (match-string 1)) | |
534 id (if (string-equal "directory" (match-string 2)) t | |
535 (if (string-equal "symbolic" (match-string 2)) "")))) | |
536 ((looking-at | |
537 "Inode:\\s-+\\([0-9]+\\)\\s-+Links:\\s-+\\([0-9]+\\)") | |
538 (setq inode (string-to-number (match-string 1)) | |
539 link (string-to-number (match-string 2)))) | |
540 ((looking-at | |
541 "Access:\\s-+([0-9]+/\\(\\S-+\\))\\s-+Uid:\\s-+\\([0-9]+\\)\\s-+Gid:\\s-+\\([0-9]+\\)") | |
542 (setq mode (match-string 1) | |
543 uid (if (equal id-format 'string) (match-string 2) | |
544 (string-to-number (match-string 2))) | |
545 gid (if (equal id-format 'string) (match-string 3) | |
546 (string-to-number (match-string 3))))) | |
547 ((looking-at | |
548 "Access:\\s-+\\([0-9]+\\)-\\([0-9]+\\)-\\([0-9]+\\)\\s-+\\([0-9]+\\):\\([0-9]+\\):\\([0-9]+\\)") | |
549 (setq atime | |
550 (encode-time | |
551 (string-to-number (match-string 6)) ;; sec | |
552 (string-to-number (match-string 5)) ;; min | |
553 (string-to-number (match-string 4)) ;; hour | |
554 (string-to-number (match-string 3)) ;; day | |
555 (string-to-number (match-string 2)) ;; month | |
556 (string-to-number (match-string 1))))) ;; year | |
557 ((looking-at | |
558 "Modify:\\s-+\\([0-9]+\\)-\\([0-9]+\\)-\\([0-9]+\\)\\s-+\\([0-9]+\\):\\([0-9]+\\):\\([0-9]+\\)") | |
559 (setq mtime | |
560 (encode-time | |
561 (string-to-number (match-string 6)) ;; sec | |
562 (string-to-number (match-string 5)) ;; min | |
563 (string-to-number (match-string 4)) ;; hour | |
564 (string-to-number (match-string 3)) ;; day | |
565 (string-to-number (match-string 2)) ;; month | |
566 (string-to-number (match-string 1))))) ;; year | |
567 ((looking-at | |
568 "Change:\\s-+\\([0-9]+\\)-\\([0-9]+\\)-\\([0-9]+\\)\\s-+\\([0-9]+\\):\\([0-9]+\\):\\([0-9]+\\)") | |
569 (setq ctime | |
570 (encode-time | |
571 (string-to-number (match-string 6)) ;; sec | |
572 (string-to-number (match-string 5)) ;; min | |
573 (string-to-number (match-string 4)) ;; hour | |
574 (string-to-number (match-string 3)) ;; day | |
575 (string-to-number (match-string 2)) ;; month | |
576 (string-to-number (match-string 1)))))) ;; year | |
577 (forward-line)) | |
578 ;; Return the result. | |
579 (list id link uid gid atime mtime ctime size mode nil inode | |
580 (tramp-get-device vec)))))) | |
466 | 581 |
467 (defun tramp-smb-handle-file-directory-p (filename) | 582 (defun tramp-smb-handle-file-directory-p (filename) |
468 "Like `file-directory-p' for Tramp files." | 583 "Like `file-directory-p' for Tramp files." |
469 (and (file-exists-p filename) | 584 (and (file-exists-p filename) |
470 (eq ?d (aref (nth 8 (file-attributes filename)) 0)))) | 585 (eq ?d (aref (nth 8 (file-attributes filename)) 0)))) |
478 (with-parsed-tramp-file-name filename nil | 593 (with-parsed-tramp-file-name filename nil |
479 (unless (file-exists-p filename) | 594 (unless (file-exists-p filename) |
480 (tramp-error | 595 (tramp-error |
481 v 'file-error | 596 v 'file-error |
482 "Cannot make local copy of non-existing file `%s'" filename)) | 597 "Cannot make local copy of non-existing file `%s'" filename)) |
483 (let ((file (tramp-smb-get-localname localname t)) | 598 (let ((file (tramp-smb-get-localname |
599 localname (not (tramp-smb-get-cifs-capabilities v)))) | |
484 (tmpfile (tramp-compat-make-temp-file filename))) | 600 (tmpfile (tramp-compat-make-temp-file filename))) |
485 (tramp-message v 4 "Fetching %s to tmp file %s..." filename tmpfile) | 601 (tramp-message v 4 "Fetching %s to tmp file %s..." filename tmpfile) |
486 (if (tramp-smb-send-command v (format "get \"%s\" %s" file tmpfile)) | 602 (if (tramp-smb-send-command v (format "get \"%s\" %s" file tmpfile)) |
487 (tramp-message | 603 (tramp-message |
488 v 4 "Fetching %s to tmp file %s...done" filename tmpfile) | 604 v 4 "Fetching %s to tmp file %s...done" filename tmpfile) |
534 (when full-directory-p | 650 (when full-directory-p |
535 ;; Called from `dired-add-entry'. | 651 ;; Called from `dired-add-entry'. |
536 (setq filename (file-name-as-directory filename))) | 652 (setq filename (file-name-as-directory filename))) |
537 (with-parsed-tramp-file-name filename nil | 653 (with-parsed-tramp-file-name filename nil |
538 (save-match-data | 654 (save-match-data |
539 (let ((base (file-name-nondirectory filename)) | 655 (let ((cifs (tramp-smb-get-cifs-capabilities v)) |
656 (base (file-name-nondirectory filename)) | |
540 ;; We should not destroy the cache entry. | 657 ;; We should not destroy the cache entry. |
541 (entries (copy-sequence | 658 (entries (copy-sequence |
542 (tramp-smb-get-file-entries | 659 (tramp-smb-get-file-entries |
543 (file-name-directory filename))))) | 660 (file-name-directory filename))))) |
544 | 661 |
590 | 707 |
591 ;; Print entries. | 708 ;; Print entries. |
592 (mapcar | 709 (mapcar |
593 (lambda (x) | 710 (lambda (x) |
594 (when (not (zerop (length (nth 0 x)))) | 711 (when (not (zerop (length (nth 0 x)))) |
595 (insert | 712 (let ((attr |
596 (format | 713 (when cifs |
597 "%10s %3d %-8s %-8s %8s %s %s\n" | 714 (file-attributes (expand-file-name (nth 0 x)) 'string)))) |
598 (nth 1 x) ; mode | 715 (insert |
599 1 "nobody" "nogroup" | 716 (format |
600 (nth 2 x) ; size | 717 "%10s %3d %-8s %-8s %8s %s %s\n" |
601 (format-time-string | 718 (or (nth 8 attr) (nth 1 x)) ; mode |
602 (if (tramp-time-less-p | 719 (or (nth 1 attr) 1) ; link |
603 (tramp-time-subtract (current-time) (nth 3 x)) | 720 (or (nth 2 attr) "nobody") ; uid |
604 tramp-half-a-year) | 721 (or (nth 3 attr) "nogroup") ; gid |
605 "%b %e %R" | 722 (nth 2 x) ; size |
606 "%b %e %Y") | 723 (format-time-string |
607 (nth 3 x)) ; date | 724 (if (tramp-time-less-p |
608 (nth 0 x))) ; file name | 725 (tramp-time-subtract (current-time) (nth 3 x)) |
609 (forward-line) | 726 tramp-half-a-year) |
610 (beginning-of-line))) | 727 "%b %e %R" |
611 entries))))) | 728 "%b %e %Y") |
729 (nth 3 x)) ; date | |
730 (nth 0 x))) ; file name | |
731 (forward-line) | |
732 (beginning-of-line)))) | |
733 entries))))) | |
612 | 734 |
613 (defun tramp-smb-handle-make-directory (dir &optional parents) | 735 (defun tramp-smb-handle-make-directory (dir &optional parents) |
614 "Like `make-directory' for Tramp files." | 736 "Like `make-directory' for Tramp files." |
615 (setq dir (directory-file-name (expand-file-name dir))) | 737 (setq dir (directory-file-name (expand-file-name dir))) |
616 (unless (file-name-absolute-p dir) | 738 (unless (file-name-absolute-p dir) |
633 (setq directory (directory-file-name (expand-file-name directory))) | 755 (setq directory (directory-file-name (expand-file-name directory))) |
634 (unless (file-name-absolute-p directory) | 756 (unless (file-name-absolute-p directory) |
635 (setq directory (expand-file-name directory default-directory))) | 757 (setq directory (expand-file-name directory default-directory))) |
636 (with-parsed-tramp-file-name directory nil | 758 (with-parsed-tramp-file-name directory nil |
637 (save-match-data | 759 (save-match-data |
638 (let* ((file (tramp-smb-get-localname localname t))) | 760 (let* ((cifs (tramp-smb-get-cifs-capabilities v)) |
761 (file (tramp-smb-get-localname localname (not cifs)))) | |
639 (when (file-directory-p (file-name-directory directory)) | 762 (when (file-directory-p (file-name-directory directory)) |
640 (tramp-smb-send-command v (format "mkdir \"%s\"" file)) | 763 (tramp-smb-send-command |
764 v | |
765 (if cifs | |
766 (format | |
767 "posix_mkdir \"%s\" %s" | |
768 file (tramp-decimal-to-octal (default-file-modes))) | |
769 (format "mkdir \"%s\"" file))) | |
641 ;; We must also flush the cache of the directory, because | 770 ;; We must also flush the cache of the directory, because |
642 ;; file-attributes reads the values from there. | 771 ;; `file-attributes' reads the values from there. |
643 (tramp-flush-file-property v localname) | 772 (tramp-flush-file-property v (file-name-directory localname)) |
644 (tramp-flush-file-property v (file-name-directory localname))) | 773 (tramp-flush-file-property v localname)) |
645 (unless (file-directory-p directory) | 774 (unless (file-directory-p directory) |
646 (tramp-error | 775 (tramp-error |
647 v 'file-error "Couldn't make directory %s" directory)))))) | 776 v 'file-error "Couldn't make directory %s" directory)))))) |
777 | |
778 (defun tramp-smb-handle-make-symbolic-link | |
779 (filename linkname &optional ok-if-already-exists) | |
780 "Like `make-symbolic-link' for Tramp files. | |
781 If LINKNAME is a non-Tramp file, it is used verbatim as the target of | |
782 the symlink. If LINKNAME is a Tramp file, only the localname component is | |
783 used as the target of the symlink. | |
784 | |
785 If LINKNAME is a Tramp file and the localname component is relative, then | |
786 it is expanded first, before the localname component is taken. Note that | |
787 this can give surprising results if the user/host for the source and | |
788 target of the symlink differ." | |
789 (unless (tramp-equal-remote filename linkname) | |
790 (with-parsed-tramp-file-name | |
791 (if (tramp-tramp-file-p filename) filename linkname) nil | |
792 (tramp-error | |
793 v 'file-error | |
794 "make-symbolic-link: %s" | |
795 "only implemented for same method, same user, same host"))) | |
796 (with-parsed-tramp-file-name filename v1 | |
797 (with-parsed-tramp-file-name linkname v2 | |
798 (when (file-directory-p filename) | |
799 (tramp-error | |
800 v2 'file-error | |
801 "make-symbolic-link: %s must not be a directory" filename)) | |
802 (when (and (not ok-if-already-exists) | |
803 (file-exists-p linkname) | |
804 (not (numberp ok-if-already-exists)) | |
805 (y-or-n-p | |
806 (format | |
807 "File %s already exists; make it a new name anyway? " | |
808 linkname))) | |
809 (tramp-error | |
810 v2 'file-error | |
811 "make-symbolic-link: file %s already exists" linkname)) | |
812 (unless (tramp-smb-get-cifs-capabilities v1) | |
813 (tramp-error v2 'file-error "make-symbolic-link not supported")) | |
814 ;; We must also flush the cache of the directory, because | |
815 ;; `file-attributes' reads the values from there. | |
816 (tramp-flush-file-property v2 (file-name-directory v2-localname)) | |
817 (tramp-flush-file-property v2 v2-localname) | |
818 (unless | |
819 (tramp-smb-send-command | |
820 v1 | |
821 (format | |
822 "symlink \"%s\" \"%s\"" | |
823 (tramp-smb-get-localname v1-localname nil) | |
824 (tramp-smb-get-localname v2-localname nil))) | |
825 (tramp-error | |
826 v2 'file-error | |
827 "error with make-symbolic-link, see buffer `%s' for details" | |
828 (buffer-name)))))) | |
648 | 829 |
649 (defun tramp-smb-handle-rename-file | 830 (defun tramp-smb-handle-rename-file |
650 (filename newname &optional ok-if-already-exists) | 831 (filename newname &optional ok-if-already-exists) |
651 "Like `rename-file' for Tramp files." | 832 "Like `rename-file' for Tramp files." |
652 (setq filename (expand-file-name filename) | 833 (setq filename (expand-file-name filename) |
670 (with-parsed-tramp-file-name newname nil | 851 (with-parsed-tramp-file-name newname nil |
671 (when (and (not ok-if-already-exists) | 852 (when (and (not ok-if-already-exists) |
672 (file-exists-p newname)) | 853 (file-exists-p newname)) |
673 (tramp-error v 'file-already-exists newname)) | 854 (tramp-error v 'file-already-exists newname)) |
674 ;; We must also flush the cache of the directory, because | 855 ;; We must also flush the cache of the directory, because |
675 ;; file-attributes reads the values from there. | 856 ;; `file-attributes' reads the values from there. |
676 (tramp-flush-file-property v (file-name-directory localname)) | 857 (tramp-flush-file-property v (file-name-directory localname)) |
677 (tramp-flush-file-property v localname) | 858 (tramp-flush-file-property v localname) |
678 (let ((file (tramp-smb-get-localname localname t))) | 859 (let ((file (tramp-smb-get-localname |
860 localname (not (tramp-smb-get-cifs-capabilities v))))) | |
679 (tramp-message v 0 "Copying file %s to file %s..." filename newname) | 861 (tramp-message v 0 "Copying file %s to file %s..." filename newname) |
680 (if (tramp-smb-send-command v (format "put %s \"%s\"" filename file)) | 862 (if (tramp-smb-send-command v (format "put %s \"%s\"" filename file)) |
681 (tramp-message | 863 (tramp-message |
682 v 0 "Copying file %s to file %s...done" filename newname) | 864 v 0 "Copying file %s to file %s...done" filename newname) |
683 (tramp-error v 'file-error "Cannot rename `%s'" filename)))))) | 865 (tramp-error v 'file-error "Cannot rename `%s'" filename)))))) |
685 (delete-file filename)) | 867 (delete-file filename)) |
686 | 868 |
687 (defun tramp-smb-handle-set-file-modes (filename mode) | 869 (defun tramp-smb-handle-set-file-modes (filename mode) |
688 "Like `set-file-modes' for Tramp files." | 870 "Like `set-file-modes' for Tramp files." |
689 (with-parsed-tramp-file-name filename nil | 871 (with-parsed-tramp-file-name filename nil |
690 (tramp-flush-file-property v localname) | 872 (when (tramp-smb-get-cifs-capabilities v) |
691 (unless (tramp-smb-send-command | 873 (tramp-flush-file-property v localname) |
692 v (format "chmod \"%s\" %s" | 874 (unless (tramp-smb-send-command |
693 (tramp-smb-get-localname localname t) | 875 v (format "chmod \"%s\" %s" |
694 (tramp-decimal-to-octal mode))) | 876 (tramp-smb-get-localname localname nil) |
695 (tramp-error | 877 (tramp-decimal-to-octal mode))) |
696 v 'file-error "Error while changing file's mode %s" filename)))) | 878 (tramp-error |
879 v 'file-error "Error while changing file's mode %s" filename))))) | |
697 | 880 |
698 (defun tramp-smb-handle-substitute-in-file-name (filename) | 881 (defun tramp-smb-handle-substitute-in-file-name (filename) |
699 "Like `handle-substitute-in-file-name' for Tramp files. | 882 "Like `handle-substitute-in-file-name' for Tramp files. |
700 \"//\" substitutes only in the local filename part. Catches | 883 \"//\" substitutes only in the local filename part. Catches |
701 errors for shares like \"C$/\", which are common in Microsoft Windows." | 884 errors for shares like \"C$/\", which are common in Microsoft Windows." |
725 (tramp-error v 'file-error "File not overwritten"))) | 908 (tramp-error v 'file-error "File not overwritten"))) |
726 ;; We must also flush the cache of the directory, because | 909 ;; We must also flush the cache of the directory, because |
727 ;; `file-attributes' reads the values from there. | 910 ;; `file-attributes' reads the values from there. |
728 (tramp-flush-file-property v (file-name-directory localname)) | 911 (tramp-flush-file-property v (file-name-directory localname)) |
729 (tramp-flush-file-property v localname) | 912 (tramp-flush-file-property v localname) |
730 (let ((file (tramp-smb-get-localname localname t)) | 913 (let ((file (tramp-smb-get-localname |
914 localname (not (tramp-smb-get-cifs-capabilities v)))) | |
731 (curbuf (current-buffer)) | 915 (curbuf (current-buffer)) |
732 (tmpfile (tramp-compat-make-temp-file filename))) | 916 (tmpfile (tramp-compat-make-temp-file filename))) |
733 ;; We say `no-message' here because we don't want the visited file | 917 ;; We say `no-message' here because we don't want the visited file |
734 ;; modtime data to be clobbered from the temp file. We call | 918 ;; modtime data to be clobbered from the temp file. We call |
735 ;; `set-visited-file-modtime' ourselves later on. | 919 ;; `set-visited-file-modtime' ourselves later on. |
976 (cdr (assoc (downcase month) tramp-parse-time-months)) | 1160 (cdr (assoc (downcase month) tramp-parse-time-months)) |
977 year) | 1161 year) |
978 '(0 0))) | 1162 '(0 0))) |
979 (list localname mode size mtime)))) | 1163 (list localname mode size mtime)))) |
980 | 1164 |
1165 (defun tramp-smb-get-cifs-capabilities (vec) | |
1166 "Check, whether the SMB server supports POSIX commands." | |
1167 (with-connection-property | |
1168 (tramp-get-connection-process vec) "cifs-capabilities" | |
1169 (when (tramp-smb-send-command vec "posix") | |
1170 (with-current-buffer (tramp-get-buffer vec) | |
1171 (goto-char (point-min)) | |
1172 (when (re-search-forward "Server supports CIFS capabilities" nil t) | |
1173 (member | |
1174 "pathnames" | |
1175 (split-string | |
1176 (buffer-substring | |
1177 (point) (tramp-compat-line-end-position)) nil t))))))) | |
1178 | |
981 | 1179 |
982 ;; Connection functions. | 1180 ;; Connection functions. |
983 | 1181 |
984 (defun tramp-smb-send-command (vec command) | 1182 (defun tramp-smb-send-command (vec command) |
985 "Send the COMMAND to connection VEC. | 1183 "Send the COMMAND to connection VEC. |
1172 ;;; TODO: | 1370 ;;; TODO: |
1173 | 1371 |
1174 ;; * Error handling in case password is wrong. | 1372 ;; * Error handling in case password is wrong. |
1175 ;; * Read password from "~/.netrc". | 1373 ;; * Read password from "~/.netrc". |
1176 ;; * Return more comprehensive file permission string. | 1374 ;; * Return more comprehensive file permission string. |
1177 ;; * Handle links (FILENAME.LNK). | |
1178 ;; * Try to remove the inclusion of dummy "" directory. Seems to be at | 1375 ;; * Try to remove the inclusion of dummy "" directory. Seems to be at |
1179 ;; several places, especially in `tramp-smb-handle-insert-directory'. | 1376 ;; several places, especially in `tramp-smb-handle-insert-directory'. |
1180 ;; * (RMS) Use unwind-protect to clean up the state so as to make the state | 1377 ;; * (RMS) Use unwind-protect to clean up the state so as to make the state |
1181 ;; regular again. | 1378 ;; regular again. |
1182 ;; * Make it multi-hop capable. | 1379 ;; * Make it multi-hop capable. |