diff options
| -rw-r--r-- | lisp/net/tramp-archive.el | 111 | ||||
| -rw-r--r-- | lisp/net/tramp-gvfs.el | 17 | ||||
| -rw-r--r-- | test/lisp/net/tramp-archive-resources/foo.tar.gz | bin | 234 -> 274 bytes | |||
| -rw-r--r-- | test/lisp/net/tramp-archive-tests.el | 32 |
4 files changed, 84 insertions, 76 deletions
diff --git a/lisp/net/tramp-archive.el b/lisp/net/tramp-archive.el index 45e3bf0a606..ac8b76b9442 100644 --- a/lisp/net/tramp-archive.el +++ b/lisp/net/tramp-archive.el | |||
| @@ -301,27 +301,42 @@ pass to the OPERATION." | |||
| 301 | t)) | 301 | t)) |
| 302 | 302 | ||
| 303 | (defvar tramp-archive-hash (make-hash-table :test 'equal) | 303 | (defvar tramp-archive-hash (make-hash-table :test 'equal) |
| 304 | "Hash table for archive local copies.") | 304 | "Hash table for archive local copies. |
| 305 | 305 | The hash key is the archive name. The value is a cons of the | |
| 306 | (defun tramp-archive-local-copy (archive) | 306 | used `tramp-file-name' structure for tramp-gvfs, and the file |
| 307 | "Return copy of ARCHIVE, usable by GVFS. | 307 | name of a local copy, if any.") |
| 308 | ARCHIVE is the archive component of an archive file name." | 308 | |
| 309 | (setq archive (file-truename archive)) | 309 | (defun tramp-archive-dissect-file-name (name) |
| 310 | (let ((tramp-verbose 0)) | 310 | "Return a `tramp-file-name' structure. |
| 311 | (with-tramp-connection-property | 311 | The structure consists of the `tramp-archive-method' method, the |
| 312 | ;; This is just an auxiliary VEC for caching properties. | 312 | hexlified archive name as host, and the localname. The archive |
| 313 | (make-tramp-file-name :method tramp-archive-method :host archive) | 313 | name is kept in slot `hop'" |
| 314 | "archive" | 314 | (save-match-data |
| 315 | (unless (tramp-archive-file-name-p name) | ||
| 316 | (tramp-compat-user-error nil "Not an archive file name: \"%s\"" name)) | ||
| 317 | ;; The `string-match' happened in `tramp-archive-file-name-p'. | ||
| 318 | (let ((archive (match-string 1 name)) | ||
| 319 | (localname (match-string 2 name)) | ||
| 320 | (tramp-verbose 0) | ||
| 321 | vec copy) | ||
| 322 | |||
| 323 | (setq archive (file-truename archive)) | ||
| 324 | |||
| 315 | (cond | 325 | (cond |
| 326 | ;; The value is already in the hash table. | ||
| 327 | ((setq vec (car (gethash archive tramp-archive-hash)))) | ||
| 328 | |||
| 316 | ;; File archives inside file archives. | 329 | ;; File archives inside file archives. |
| 317 | ((tramp-archive-file-name-p archive) | 330 | ((tramp-archive-file-name-p archive) |
| 318 | (let ((archive | 331 | (let ((archive |
| 319 | (tramp-make-tramp-file-name | 332 | (tramp-make-tramp-file-name |
| 320 | (tramp-archive-dissect-file-name archive) nil 'noarchive))) | 333 | (tramp-archive-dissect-file-name archive) nil 'noarchive))) |
| 321 | ;; We call `file-attributes' in order to mount the archive. | 334 | (setq vec |
| 322 | (file-attributes archive) | 335 | (make-tramp-file-name |
| 323 | (puthash archive nil tramp-archive-hash) | 336 | :method tramp-archive-method :hop archive |
| 324 | archive)) | 337 | :host (url-hexify-string (tramp-gvfs-url-file-name archive))))) |
| 338 | (puthash archive (list vec) tramp-archive-hash)) | ||
| 339 | |||
| 325 | ;; http://... | 340 | ;; http://... |
| 326 | ((and url-handler-mode | 341 | ((and url-handler-mode |
| 327 | tramp-compat-use-url-tramp-p | 342 | tramp-compat-use-url-tramp-p |
| @@ -332,26 +347,36 @@ ARCHIVE is the archive component of an archive file name." | |||
| 332 | (url-type (url-generic-parse-url archive)) | 347 | (url-type (url-generic-parse-url archive)) |
| 333 | url-tramp-protocols)) | 348 | url-tramp-protocols)) |
| 334 | (archive (url-tramp-convert-url-to-tramp archive))) | 349 | (archive (url-tramp-convert-url-to-tramp archive))) |
| 335 | (puthash archive nil tramp-archive-hash) | 350 | (setq vec |
| 336 | archive)) | 351 | (make-tramp-file-name |
| 352 | :method tramp-archive-method :hop archive | ||
| 353 | :host (url-hexify-string (tramp-gvfs-url-file-name archive))))) | ||
| 354 | (puthash archive (list vec) tramp-archive-hash)) | ||
| 355 | |||
| 337 | ;; GVFS supported schemes. | 356 | ;; GVFS supported schemes. |
| 338 | ((or (tramp-gvfs-file-name-p archive) | 357 | ((or (tramp-gvfs-file-name-p archive) |
| 339 | (not (file-remote-p archive))) | 358 | (not (file-remote-p archive))) |
| 340 | (puthash archive nil tramp-archive-hash) | 359 | (setq vec |
| 341 | archive) | 360 | (make-tramp-file-name |
| 361 | :method tramp-archive-method :hop archive | ||
| 362 | :host (url-hexify-string (tramp-gvfs-url-file-name archive)))) | ||
| 363 | (puthash archive (list vec) tramp-archive-hash)) | ||
| 364 | |||
| 342 | ;; Anything else. Here we call `file-local-copy', which we | 365 | ;; Anything else. Here we call `file-local-copy', which we |
| 343 | ;; have avoided so far. | 366 | ;; have avoided so far. |
| 344 | (t (let ((inhibit-file-name-operation 'file-local-copy) | 367 | (t (let ((inhibit-file-name-operation 'file-local-copy) |
| 345 | (inhibit-file-name-handlers | 368 | (inhibit-file-name-handlers |
| 346 | (cons 'jka-compr-handler inhibit-file-name-handlers)) | 369 | (cons 'jka-compr-handler inhibit-file-name-handlers))) |
| 347 | result) | 370 | (setq copy (file-local-copy archive) |
| 348 | (or (and (setq result (gethash archive tramp-archive-hash nil)) | 371 | vec |
| 349 | (file-readable-p result)) | 372 | (make-tramp-file-name |
| 350 | (puthash | 373 | :method tramp-archive-method :hop archive |
| 351 | archive | 374 | :host (url-hexify-string (tramp-gvfs-url-file-name copy))))) |
| 352 | (setq result (file-local-copy archive)) | 375 | (puthash archive (cons vec copy) tramp-archive-hash))) |
| 353 | tramp-archive-hash)) | 376 | |
| 354 | result)))))) | 377 | ;; So far, `vec' handles just the mount point. Add `localname'. |
| 378 | (setf (tramp-file-name-localname vec) localname) | ||
| 379 | vec))) | ||
| 355 | 380 | ||
| 356 | ;;;###tramp-autoload | 381 | ;;;###tramp-autoload |
| 357 | (defun tramp-archive-cleanup-hash () | 382 | (defun tramp-archive-cleanup-hash () |
| @@ -360,16 +385,10 @@ ARCHIVE is the archive component of an archive file name." | |||
| 360 | (lambda (key value) | 385 | (lambda (key value) |
| 361 | ;; Unmount local copy. | 386 | ;; Unmount local copy. |
| 362 | (ignore-errors | 387 | (ignore-errors |
| 363 | (let ((tramp-gvfs-methods tramp-archive-all-gvfs-methods) | 388 | (tramp-message (car value) 3 "Unmounting %s" (or (cdr value) key)) |
| 364 | (file-archive (file-name-as-directory key))) | 389 | (tramp-gvfs-unmount (car value))) |
| 365 | (tramp-message | ||
| 366 | (and (tramp-tramp-file-p key) (tramp-dissect-file-name key)) 3 | ||
| 367 | "Unmounting %s" file-archive) | ||
| 368 | (tramp-gvfs-unmount | ||
| 369 | (tramp-dissect-file-name | ||
| 370 | (tramp-archive-gvfs-file-name file-archive))))) | ||
| 371 | ;; Delete local copy. | 390 | ;; Delete local copy. |
| 372 | (ignore-errors (when value (delete-file value))) | 391 | (ignore-errors (delete-file (cdr value))) |
| 373 | (remhash key tramp-archive-hash)) | 392 | (remhash key tramp-archive-hash)) |
| 374 | tramp-archive-hash) | 393 | tramp-archive-hash) |
| 375 | (clrhash tramp-archive-hash)) | 394 | (clrhash tramp-archive-hash)) |
| @@ -380,24 +399,6 @@ ARCHIVE is the archive component of an archive file name." | |||
| 380 | (remove-hook 'kill-emacs-hook | 399 | (remove-hook 'kill-emacs-hook |
| 381 | 'tramp-archive-cleanup-hash))) | 400 | 'tramp-archive-cleanup-hash))) |
| 382 | 401 | ||
| 383 | (defun tramp-archive-dissect-file-name (name) | ||
| 384 | "Return a `tramp-file-name' structure. | ||
| 385 | The structure consists of the `tramp-archive-method' method, the | ||
| 386 | hexlified archive name as host, and the localname. The archive | ||
| 387 | name is kept in slot `hop'" | ||
| 388 | (save-match-data | ||
| 389 | (unless (tramp-archive-file-name-p name) | ||
| 390 | (tramp-compat-user-error nil "Not an archive file name: \"%s\"" name)) | ||
| 391 | ;; The `string-match' happened in `tramp-archive-file-name-p'. | ||
| 392 | (let ((archive (match-string 1 name)) | ||
| 393 | (localname (match-string 2 name)) | ||
| 394 | (tramp-verbose 0)) | ||
| 395 | (make-tramp-file-name | ||
| 396 | :method tramp-archive-method :user nil :domain nil :host | ||
| 397 | (url-hexify-string | ||
| 398 | (tramp-gvfs-url-file-name (tramp-archive-local-copy archive))) | ||
| 399 | :port nil :localname localname :hop archive)))) | ||
| 400 | |||
| 401 | (defsubst tramp-file-name-archive (vec) | 402 | (defsubst tramp-file-name-archive (vec) |
| 402 | "Extract the archive file name from VEC. | 403 | "Extract the archive file name from VEC. |
| 403 | VEC is expected to be a `tramp-file-name', with the method being | 404 | VEC is expected to be a `tramp-file-name', with the method being |
diff --git a/lisp/net/tramp-gvfs.el b/lisp/net/tramp-gvfs.el index 6745ae02c7b..70ac077a7c5 100644 --- a/lisp/net/tramp-gvfs.el +++ b/lisp/net/tramp-gvfs.el | |||
| @@ -1778,13 +1778,16 @@ file-notify events." | |||
| 1778 | 1778 | ||
| 1779 | (defun tramp-gvfs-unmount (vec) | 1779 | (defun tramp-gvfs-unmount (vec) |
| 1780 | "Unmount the object identified by VEC." | 1780 | "Unmount the object identified by VEC." |
| 1781 | (let ((vec (copy-tramp-file-name vec))) | 1781 | (setf (tramp-file-name-localname vec) "/" |
| 1782 | (setf (tramp-file-name-localname vec) "/" | 1782 | (tramp-file-name-hop vec) nil) |
| 1783 | (tramp-file-name-hop vec) nil) | 1783 | (when (tramp-gvfs-connection-mounted-p vec) |
| 1784 | (when (tramp-gvfs-connection-mounted-p vec) | 1784 | (tramp-gvfs-send-command |
| 1785 | (tramp-gvfs-send-command | 1785 | vec "gvfs-mount" "-u" |
| 1786 | vec "gvfs-mount" "-u" | 1786 | (tramp-gvfs-url-file-name (tramp-make-tramp-file-name vec)))) |
| 1787 | (tramp-gvfs-url-file-name (tramp-make-tramp-file-name vec)))))) | 1787 | (while (tramp-gvfs-connection-mounted-p vec) |
| 1788 | (read-event nil nil 0.1)) | ||
| 1789 | (tramp-flush-connection-properties vec) | ||
| 1790 | (tramp-flush-connection-properties (tramp-get-connection-process vec))) | ||
| 1788 | 1791 | ||
| 1789 | (defun tramp-gvfs-mount-spec-entry (key value) | 1792 | (defun tramp-gvfs-mount-spec-entry (key value) |
| 1790 | "Construct a mount-spec entry to be used in a mount_spec. | 1793 | "Construct a mount-spec entry to be used in a mount_spec. |
diff --git a/test/lisp/net/tramp-archive-resources/foo.tar.gz b/test/lisp/net/tramp-archive-resources/foo.tar.gz index 68925b147fc..0d2e9878dd7 100644 --- a/test/lisp/net/tramp-archive-resources/foo.tar.gz +++ b/test/lisp/net/tramp-archive-resources/foo.tar.gz | |||
| Binary files differ | |||
diff --git a/test/lisp/net/tramp-archive-tests.el b/test/lisp/net/tramp-archive-tests.el index 149ed370432..82dd5de8b9a 100644 --- a/test/lisp/net/tramp-archive-tests.el +++ b/test/lisp/net/tramp-archive-tests.el | |||
| @@ -99,9 +99,9 @@ variables, so we check the Emacs version directly." | |||
| 99 | (tramp-archive-file-name-p (concat tramp-archive-test-archive "foo/bar"))) | 99 | (tramp-archive-file-name-p (concat tramp-archive-test-archive "foo/bar"))) |
| 100 | ;; A file archive inside a file archive. | 100 | ;; A file archive inside a file archive. |
| 101 | (should | 101 | (should |
| 102 | (tramp-archive-file-name-p (concat tramp-archive-test-archive "foo.tar"))) | 102 | (tramp-archive-file-name-p (concat tramp-archive-test-archive "baz.tar"))) |
| 103 | (should | 103 | (should |
| 104 | (tramp-archive-file-name-p (concat tramp-archive-test-archive "foo.tar/")))) | 104 | (tramp-archive-file-name-p (concat tramp-archive-test-archive "baz.tar/")))) |
| 105 | 105 | ||
| 106 | (ert-deftest tramp-archive-test02-file-name-dissect () | 106 | (ert-deftest tramp-archive-test02-file-name-dissect () |
| 107 | "Check archive file name components." | 107 | "Check archive file name components." |
| @@ -145,13 +145,14 @@ variables, so we check the Emacs version directly." | |||
| 145 | 145 | ||
| 146 | ;; File archive in file archive. | 146 | ;; File archive in file archive. |
| 147 | (let* ((tramp-archive-test-file-archive | 147 | (let* ((tramp-archive-test-file-archive |
| 148 | (concat tramp-archive-test-archive "bar.tar")) | 148 | (concat tramp-archive-test-archive "baz.tar")) |
| 149 | (tramp-archive-test-archive | 149 | (tramp-archive-test-archive |
| 150 | (file-name-as-directory tramp-archive-test-file-archive)) | 150 | (file-name-as-directory tramp-archive-test-file-archive)) |
| 151 | (tramp-methods (cons `(,tramp-archive-method) tramp-methods)) | 151 | (tramp-methods (cons `(,tramp-archive-method) tramp-methods)) |
| 152 | (tramp-gvfs-methods tramp-archive-all-gvfs-methods)) | 152 | (tramp-gvfs-methods tramp-archive-all-gvfs-methods)) |
| 153 | (unwind-protect | 153 | (unwind-protect |
| 154 | (with-parsed-tramp-archive-file-name tramp-archive-test-archive nil | 154 | (with-parsed-tramp-archive-file-name |
| 155 | (expand-file-name "bar" tramp-archive-test-archive) nil | ||
| 155 | (should (string-equal method tramp-archive-method)) | 156 | (should (string-equal method tramp-archive-method)) |
| 156 | (should-not user) | 157 | (should-not user) |
| 157 | (should-not domain) | 158 | (should-not domain) |
| @@ -184,8 +185,12 @@ variables, so we check the Emacs version directly." | |||
| 184 | nil "/")) | 185 | nil "/")) |
| 185 | (file-name-nondirectory tramp-archive-test-file-archive))))) | 186 | (file-name-nondirectory tramp-archive-test-file-archive))))) |
| 186 | (should-not port) | 187 | (should-not port) |
| 187 | (should (string-equal localname "/")) | 188 | (should (string-equal localname "/bar")) |
| 188 | (should (string-equal archive tramp-archive-test-file-archive))) | 189 | ;; The `archive' component is now already a Tramp file name. |
| 190 | (should | ||
| 191 | (string-equal | ||
| 192 | archive | ||
| 193 | (tramp-archive-gvfs-file-name tramp-archive-test-file-archive)))) | ||
| 189 | 194 | ||
| 190 | ;; Cleanup. | 195 | ;; Cleanup. |
| 191 | (tramp-archive-cleanup-hash)))) | 196 | (tramp-archive-cleanup-hash)))) |
| @@ -290,9 +295,8 @@ This checks also `file-name-as-directory', `file-name-directory', | |||
| 290 | :type tramp-file-missing)) | 295 | :type tramp-file-missing)) |
| 291 | 296 | ||
| 292 | ;; Cleanup. | 297 | ;; Cleanup. |
| 293 | (ignore-errors | 298 | (ignore-errors (tramp-archive--test-delete tmp-name)) |
| 294 | (tramp-archive--test-delete tmp-name) | 299 | (tramp-archive-cleanup-hash)))) |
| 295 | (tramp-archive-cleanup-hash))))) | ||
| 296 | 300 | ||
| 297 | (ert-deftest tramp-archive-test09-insert-file-contents () | 301 | (ert-deftest tramp-archive-test09-insert-file-contents () |
| 298 | "Check `insert-file-contents'." | 302 | "Check `insert-file-contents'." |
| @@ -444,7 +448,7 @@ This checks also `file-name-as-directory', `file-name-directory', | |||
| 444 | (skip-unless tramp-gvfs-enabled) | 448 | (skip-unless tramp-gvfs-enabled) |
| 445 | 449 | ||
| 446 | (let ((tmp-name tramp-archive-test-archive) | 450 | (let ((tmp-name tramp-archive-test-archive) |
| 447 | (files '("." ".." "bar" "foo.hrd" "foo.lnk" "foo.txt"))) | 451 | (files '("." ".." "bar" "baz.tar" "foo.hrd" "foo.lnk" "foo.txt"))) |
| 448 | (unwind-protect | 452 | (unwind-protect |
| 449 | (progn | 453 | (progn |
| 450 | (should (file-directory-p tmp-name)) | 454 | (should (file-directory-p tmp-name)) |
| @@ -656,7 +660,7 @@ This tests also `file-executable-p', `file-writable-p' and `set-file-modes'." | |||
| 656 | ;; Local files. | 660 | ;; Local files. |
| 657 | (should (equal (file-name-completion "fo" tmp-name) "foo.")) | 661 | (should (equal (file-name-completion "fo" tmp-name) "foo.")) |
| 658 | (should (equal (file-name-completion "foo.txt" tmp-name) t)) | 662 | (should (equal (file-name-completion "foo.txt" tmp-name) t)) |
| 659 | (should (equal (file-name-completion "b" tmp-name) "bar/")) | 663 | (should (equal (file-name-completion "b" tmp-name) "ba")) |
| 660 | (should-not (file-name-completion "a" tmp-name)) | 664 | (should-not (file-name-completion "a" tmp-name)) |
| 661 | (should | 665 | (should |
| 662 | (equal | 666 | (equal |
| @@ -668,18 +672,18 @@ This tests also `file-executable-p', `file-writable-p' and `set-file-modes'." | |||
| 668 | (should | 672 | (should |
| 669 | (equal | 673 | (equal |
| 670 | (sort (file-name-all-completions "b" tmp-name) 'string-lessp) | 674 | (sort (file-name-all-completions "b" tmp-name) 'string-lessp) |
| 671 | '("bar/"))) | 675 | '("bar/" "baz.tar"))) |
| 672 | (should-not (file-name-all-completions "a" tmp-name)) | 676 | (should-not (file-name-all-completions "a" tmp-name)) |
| 673 | ;; `completion-regexp-list' restricts the completion to | 677 | ;; `completion-regexp-list' restricts the completion to |
| 674 | ;; files which match all expressions in this list. | 678 | ;; files which match all expressions in this list. |
| 675 | (let ((completion-regexp-list | 679 | (let ((completion-regexp-list |
| 676 | `(,directory-files-no-dot-files-regexp "b"))) | 680 | `(,directory-files-no-dot-files-regexp "b"))) |
| 677 | (should | 681 | (should |
| 678 | (equal (file-name-completion "" tmp-name) "bar/")) | 682 | (equal (file-name-completion "" tmp-name) "ba")) |
| 679 | (should | 683 | (should |
| 680 | (equal | 684 | (equal |
| 681 | (sort (file-name-all-completions "" tmp-name) 'string-lessp) | 685 | (sort (file-name-all-completions "" tmp-name) 'string-lessp) |
| 682 | '("bar/"))))) | 686 | '("bar/" "baz.tar"))))) |
| 683 | 687 | ||
| 684 | ;; Cleanup. | 688 | ;; Cleanup. |
| 685 | (tramp-archive-cleanup-hash)))) | 689 | (tramp-archive-cleanup-hash)))) |