diff options
| author | Michael Albinus | 2009-10-11 14:02:23 +0000 |
|---|---|---|
| committer | Michael Albinus | 2009-10-11 14:02:23 +0000 |
| commit | f6f7e059f72317c02daec44b209093eddf88af7d (patch) | |
| tree | 17c952a527454e6138d16c4fe0854e467d08deeb | |
| parent | 674a9263fd261f9202c2b602fd0def8ca0165b42 (diff) | |
| download | emacs-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/ChangeLog | 28 | ||||
| -rw-r--r-- | lisp/net/tramp-smb.el | 401 |
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 @@ | |||
| 1 | 2009-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 | |||
| 1 | 2009-10-11 Chong Yidong <cyd@stupidchicken.com> | 29 | 2009-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. | ||
| 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)))))) | ||
| 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 |