aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael Albinus2009-10-11 14:02:23 +0000
committerMichael Albinus2009-10-11 14:02:23 +0000
commitf6f7e059f72317c02daec44b209093eddf88af7d (patch)
tree17c952a527454e6138d16c4fe0854e467d08deeb
parent674a9263fd261f9202c2b602fd0def8ca0165b42 (diff)
downloademacs-f6f7e059f72317c02daec44b209093eddf88af7d.tar.gz
emacs-f6f7e059f72317c02daec44b209093eddf88af7d.zip
* 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.
-rw-r--r--lisp/ChangeLog28
-rw-r--r--lisp/net/tramp-smb.el401
2 files changed, 327 insertions, 102 deletions
diff --git a/lisp/ChangeLog b/lisp/ChangeLog
index 523431ede66..6ee4ffccb25 100644
--- a/lisp/ChangeLog
+++ b/lisp/ChangeLog
@@ -1,3 +1,31 @@
12009-10-11 Michael Albinus <michael.albinus@gmx.de>
2
3 * net/tramp.el (tramp-local-host-p): Function shall return nil for
4 connection methods like smb.
5
6 * net/tramp-cache.el (tramp-flush-connection-property): The hash
7 can be empty.
8
9 * net/tramp-smb.el (tramp-smb-errors): Add error messages.
10 (tramp-smb-file-name-handler-alist): Add handlers for
11 `add-name-to-file', `make-symbolic-link'.
12 (tramp-smb-handle-add-name-to-file)
13 (tramp-do-file-attributes-with-stat)
14 (tramp-smb-handle-make-symbolic-link)
15 (tramp-smb-get-cifs-capabilities): New defuns.
16 (tramp-smb-handle-copy-directory, tramp-smb-handle-copy-file)
17 (tramp-smb-handle-delete-directory, tramp-smb-handle-delete-file)
18 (tramp-smb-handle-file-local-copy)
19 (tramp-smb-handle-make-directory-internal)
20 (tramp-smb-handle-rename-file, tramp-smb-handle-write-region): The
21 file name syntax depends on cifs capabilities.
22 (tramp-smb-handle-file-attributes); Call
23 `tramp-do-file-attributes-with-stat' if possible.
24 (tramp-smb-handle-insert-directory): Use posix attributes if
25 possible.
26 (tramp-smb-handle-set-file-modes): It is applicable for posix
27 only.
28
12009-10-11 Chong Yidong <cyd@stupidchicken.com> 292009-10-11 Chong Yidong <cyd@stupidchicken.com>
2 30
3 * emacs-lisp/eieio.el: Avoid requiring cl at runtime. 31 * emacs-lisp/eieio.el: Avoid requiring cl at runtime.
diff --git a/lisp/net/tramp-smb.el b/lisp/net/tramp-smb.el
index b139b3de189..d50b1aaf9f6 100644
--- a/lisp/net/tramp-smb.el
+++ b/lisp/net/tramp-smb.el
@@ -95,6 +95,7 @@
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"
@@ -131,7 +132,7 @@ See `tramp-actions-before-shell' for more info.")
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)
@@ -175,7 +176,7 @@ See `tramp-actions-before-shell' for more info.")
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)
@@ -210,6 +211,50 @@ pass to the OPERATION."
210 211
211;; File name primitives. 212;; File name primitives.
212 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)))))))
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."
@@ -234,7 +279,8 @@ pass to the OPERATION."
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
@@ -242,8 +288,9 @@ pass to the OPERATION."
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
@@ -256,8 +303,8 @@ pass to the OPERATION."
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")))))
@@ -295,11 +342,12 @@ PRESERVE-UID-GID is completely ignored."
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))
@@ -328,23 +376,21 @@ PRESERVE-UID-GID is completely ignored."
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."
@@ -352,23 +398,21 @@ PRESERVE-UID-GID is completely ignored."
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)
@@ -433,36 +477,107 @@ PRESERVE-UID-GID is completely ignored."
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."
@@ -480,7 +595,8 @@ PRESERVE-UID-GID is completely ignored."
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))
@@ -536,7 +652,8 @@ PRESERVE-UID-GID is completely ignored."
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
@@ -592,23 +709,28 @@ PRESERVE-UID-GID is completely ignored."
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."
@@ -635,17 +757,76 @@ PRESERVE-UID-GID is completely ignored."
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))))))
648 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.
781If LINKNAME is a non-Tramp file, it is used verbatim as the target of
782the symlink. If LINKNAME is a Tramp file, only the localname component is
783used as the target of the symlink.
784
785If LINKNAME is a Tramp file and the localname component is relative, then
786it is expanded first, before the localname component is taken. Note that
787this can give surprising results if the user/host for the source and
788target 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))))))
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."
@@ -672,10 +853,11 @@ PRESERVE-UID-GID is completely ignored."
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
@@ -687,13 +869,14 @@ PRESERVE-UID-GID is completely ignored."
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.
@@ -727,7 +910,8 @@ errors for shares like \"C$/\", which are common in Microsoft Windows."
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
@@ -978,6 +1162,20 @@ Result is the list (LOCALNAME MODE SIZE MTIME)."
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
@@ -1174,7 +1372,6 @@ Returns nil if an error message has appeared."
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