comment fix
[bpt/emacs.git] / lisp / tar-mode.el
index c7ebfc9..5c5bdae 100644 (file)
@@ -111,7 +111,7 @@ how many null padding bytes go on the end of the tar file."
   :group 'tar)
 
 (defcustom tar-update-datestamp nil
-  "*Non-nil means tar-mode should play fast and loose with sub-file datestamps.
+  "*Non-nil means Tar mode should play fast and loose with sub-file datestamps.
 If this is true, then editing and saving a tar file entry back into its
 tar file will update its datestamp.  If false, the datestamp is unchanged.
 You may or may not want this - it is good in that you can tell when a file
@@ -128,6 +128,7 @@ This information is useful, but it takes screen space away from file names."
   :group 'tar)
 
 (defvar tar-parse-info nil)
+;; Be sure that this variable holds byte position, not char position.
 (defvar tar-header-offset nil)
 (defvar tar-superior-buffer nil)
 (defvar tar-superior-descriptor nil)
@@ -138,9 +139,6 @@ This information is useful, but it takes screen space away from file names."
 (put 'tar-superior-buffer 'permanent-local t)
 (put 'tar-superior-descriptor 'permanent-local t)
 \f
-;;; First, duplicate some Common Lisp functions; I used to just (require 'cl)
-;;; but "cl.el" was messing some people up (also it's really big).
-
 (defmacro tar-setf (form val)
   "A mind-numbingly simple implementation of setf."
   (let ((mform (macroexpand form (and (boundp 'byte-compile-macro-environment)
@@ -154,34 +152,6 @@ This information is useful, but it takes screen space away from file names."
          ((eq (car mform) 'cdr)
           (list 'setcdr (nth 1 mform) val))
          (t (error "don't know how to setf %s" form)))))
-
-(defmacro tar-dolist (control &rest body)
-  "syntax: (dolist (var-name list-expr &optional return-value) &body body)"
-  (let ((var (car control))
-       (init (car (cdr control)))
-       (val (car (cdr (cdr control)))))
-    (list 'let (list (list '_dolist_iterator_ init))
-         (list 'while '_dolist_iterator_
-           (cons 'let
-             (cons (list (list var '(car _dolist_iterator_)))
-                   (append body
-                           (list (list 'setq '_dolist_iterator_
-                                       (list 'cdr '_dolist_iterator_)))))))
-         val)))
-
-(defmacro tar-dotimes (control &rest body)
-  "syntax: (dolist (var-name count-expr &optional return-value) &body body)"
-  (let ((var (car control))
-       (n (car (cdr control)))
-       (val (car (cdr (cdr control)))))
-    (list 'let (list (list '_dotimes_end_ n)
-                    (list var 0))
-         (cons 'while
-               (cons (list '< var '_dotimes_end_)
-                     (append body
-                             (list (list 'setq var (list '1+ var))))))
-         val)))
-
 \f
 ;;; down to business.
 
@@ -243,32 +213,44 @@ write-date, checksum, link-type, and link-name."
                (link-p (aref string tar-linkp-offset))
                (magic-str (substring string tar-magic-offset (1- tar-uname-offset)))
                (uname-valid-p (or (string= "ustar  " magic-str) (string= "GNUtar " magic-str)))
-               name
+               name linkname
                (nulsexp   "[^\000]*\000"))
-          (and (string-match nulsexp string tar-name-offset) (setq name-end (min name-end (1- (match-end 0)))))
-          (and (string-match nulsexp string tar-link-offset) (setq link-end (min link-end (1- (match-end 0)))))
-          (and (string-match nulsexp string tar-uname-offset) (setq uname-end (min uname-end (1- (match-end 0)))))
-          (and (string-match nulsexp string tar-gname-offset) (setq gname-end (min gname-end (1- (match-end 0)))))
+          (when (string-match nulsexp string tar-name-offset)
+            (setq name-end (min name-end (1- (match-end 0)))))
+          (when (string-match nulsexp string tar-link-offset)
+            (setq link-end (min link-end (1- (match-end 0)))))
+          (when (string-match nulsexp string tar-uname-offset)
+            (setq uname-end (min uname-end (1- (match-end 0)))))
+          (when (string-match nulsexp string tar-gname-offset)
+            (setq gname-end (min gname-end (1- (match-end 0)))))
           (setq name (substring string tar-name-offset name-end)
                 link-p (if (or (= link-p 0) (= link-p ?0))
                            nil
                          (- link-p ?0)))
+          (setq linkname (substring string tar-link-offset link-end))
+          (if default-enable-multibyte-characters
+              (setq name
+                    (decode-coding-string name (or file-name-coding-system
+                                                   'undecided))
+                    linkname
+                    (decode-coding-string linkname (or file-name-coding-system
+                                                       'undecided))))
           (if (and (null link-p) (string-match "/$" name)) (setq link-p 5)) ; directory
           (make-tar-header
             name
-            (tar-parse-octal-integer string tar-mode-offset (1- tar-uid-offset))
-            (tar-parse-octal-integer string tar-uid-offset (1- tar-gid-offset))
-            (tar-parse-octal-integer string tar-gid-offset (1- tar-size-offset))
-            (tar-parse-octal-integer string tar-size-offset (1- tar-time-offset))
-            (tar-parse-octal-long-integer string tar-time-offset (1- tar-chk-offset))
-            (tar-parse-octal-integer string tar-chk-offset (1- tar-linkp-offset))
+            (tar-parse-octal-integer string tar-mode-offset tar-uid-offset)
+            (tar-parse-octal-integer string tar-uid-offset tar-gid-offset)
+            (tar-parse-octal-integer string tar-gid-offset tar-size-offset)
+            (tar-parse-octal-integer string tar-size-offset tar-time-offset)
+            (tar-parse-octal-long-integer string tar-time-offset tar-chk-offset)
+            (tar-parse-octal-integer string tar-chk-offset tar-linkp-offset)
             link-p
-            (substring string tar-link-offset link-end)
+            linkname
             uname-valid-p
             (and uname-valid-p (substring string tar-uname-offset uname-end))
             (and uname-valid-p (substring string tar-gname-offset gname-end))
-            (tar-parse-octal-integer string tar-dmaj-offset (1- tar-dmin-offset))
-            (tar-parse-octal-integer string tar-dmin-offset (1- tar-end-offset))
+            (tar-parse-octal-integer string tar-dmaj-offset tar-dmin-offset)
+            (tar-parse-octal-integer string tar-dmin-offset tar-end-offset)
             )))
        (t 'empty-tar-block)))
 
@@ -303,10 +285,10 @@ write-date, checksum, link-type, and link-name."
 (defun tar-parse-octal-integer-safe (string)
   (let ((L (length string)))
     (if (= L 0) (error "empty string"))
-    (tar-dotimes (i L)
+    (dotimes (i L)
        (if (or (< (aref string i) ?0)
               (> (aref string i) ?7))
-          (error "'%c' is not an octal digit"))))
+          (error "`%c' is not an octal digit"))))
   (tar-parse-octal-integer string))
 
 
@@ -332,38 +314,26 @@ write-date, checksum, link-type, and link-name."
   (if (not (= desired-checksum (tar-header-block-checksum hblock)))
       (progn (beep) (message "Invalid checksum for file %s!" file-name))))
 
-(defun tar-header-block-recompute-checksum (hblock)
-  "Modifies the given string to have a valid checksum field."
-  (let* ((chk (tar-header-block-checksum hblock))
-        (chk-string (format "%6o" chk))
-        (l (length chk-string)))
-    (aset hblock 154 0)
-    (aset hblock 155 32)
-    (tar-dotimes (i l) (aset hblock (- 153 i) (aref chk-string (- l i 1)))))
-  hblock)
-
 (defun tar-clip-time-string (time)
   (let ((str (current-time-string time)))
-    (concat (substring str 4 16) (substring str 19 24))))
+    (concat " " (substring str 4 16) (substring str 19 24))))
 
-(defun tar-grind-file-mode (mode string start)
-  "Store `-rw--r--r--' indicating MODE into STRING beginning at START.
+(defun tar-grind-file-mode (mode)
+  "Construct a `-rw--r--r--' string indicating MODE.
 MODE should be an integer which is a file mode value."
-  (aset string start       (if (zerop (logand 256 mode)) ?- ?r))
-  (aset string (+ start 1) (if (zerop (logand 128 mode)) ?- ?w))
-  (aset string (+ start 2) (if (zerop (logand  64 mode)) ?- ?x)) 
-  (aset string (+ start 3) (if (zerop (logand  32 mode)) ?- ?r))
-  (aset string (+ start 4) (if (zerop (logand  16 mode)) ?- ?w))
-  (aset string (+ start 5) (if (zerop (logand   8 mode)) ?- ?x))
-  (aset string (+ start 6) (if (zerop (logand   4 mode)) ?- ?r))
-  (aset string (+ start 7) (if (zerop (logand   2 mode)) ?- ?w))
-  (aset string (+ start 8) (if (zerop (logand   1 mode)) ?- ?x))
-  (if (zerop (logand 1024 mode)) nil (aset string (+ start 2) ?s))
-  (if (zerop (logand 2048 mode)) nil (aset string (+ start 5) ?s))
-  string)
+  (string
+   (if (zerop (logand 256 mode)) ?- ?r)
+   (if (zerop (logand 128 mode)) ?- ?w)
+   (if (zerop (logand 1024 mode)) (if (zerop (logand  64 mode)) ?- ?x) ?s)
+   (if (zerop (logand  32 mode)) ?- ?r)
+   (if (zerop (logand  16 mode)) ?- ?w)
+   (if (zerop (logand 2048 mode)) (if (zerop (logand   8 mode)) ?- ?x) ?s)
+   (if (zerop (logand   4 mode)) ?- ?r)
+   (if (zerop (logand   2 mode)) ?- ?w)
+   (if (zerop (logand   1 mode)) ?- ?x)))
 
 (defun tar-header-block-summarize (tar-hblock &optional mod-p)
-  "Returns a line similar to the output of `tar -vtf'."
+  "Return a line similar to the output of `tar -vtf'."
   (let ((name (tar-header-name tar-hblock))
        (mode (tar-header-mode tar-hblock))
        (uid (tar-header-uid tar-hblock))
@@ -373,60 +343,39 @@ MODE should be an integer which is a file mode value."
        (size (tar-header-size tar-hblock))
        (time (tar-header-date tar-hblock))
        (ck (tar-header-checksum tar-hblock))
-       (link-p (tar-header-link-type tar-hblock))
-       (link-name (tar-header-link-name tar-hblock))
-       )
-    (let* ((left 11)
-          (namew 8)
-          (groupw 8)
-          (sizew 8)
-          (datew (if tar-mode-show-date 18 0))
-          (slash (1- (+ left namew)))
-          (lastdigit (+ slash groupw sizew))
-          (datestart (+ lastdigit 2))
-          (namestart (+ datestart datew))
-          (string (make-string (+ namestart (length name) (if link-p (+ 5 (length link-name)) 0)) 32))
-          (type (tar-header-link-type tar-hblock)))
-      (aset string 0 (if mod-p ?* ? ))
-      (aset string 1
+       (type (tar-header-link-type tar-hblock))
+       (link-name (tar-header-link-name tar-hblock)))
+    (format "%c%c%s%8s/%-8s%7s%s %s%s"
+           (if mod-p ?* ? )
            (cond ((or (eq type nil) (eq type 0)) ?-)
-                 ((eq type 1) ?l)  ; link
-                 ((eq type 2) ?s)  ; symlink
-                 ((eq type 3) ?c)  ; char special
-                 ((eq type 4) ?b)  ; block special
-                 ((eq type 5) ?d)  ; directory
-                 ((eq type 6) ?p)  ; FIFO/pipe
-                 ((eq type 20) ?*) ; directory listing
-                 ((eq type 29) ?M) ; multivolume continuation
-                 ((eq type 35) ?S) ; sparse
-                 ((eq type 38) ?V) ; volume header
-                 ))
-      (tar-grind-file-mode mode string 2)
-      (setq uid (if (= 0 (length uname)) (int-to-string uid) uname))
-      (setq gid (if (= 0 (length gname)) (int-to-string gid) gname))
-      (setq size (int-to-string size))
-      (setq time (tar-clip-time-string time))
-      (tar-dotimes (i (min (1- namew) (length uid))) (aset string (- slash i) (aref uid (- (length uid) i 1))))
-      (aset string (1+ slash) ?/)
-      (tar-dotimes (i (min (1- groupw) (length gid))) (aset string (+ (+ slash 2) i) (aref gid i)))
-      (tar-dotimes (i (min sizew (length size))) (aset string (- lastdigit i) (aref size (- (length size) i 1))))
-      (if tar-mode-show-date
-         (tar-dotimes (i (length time)) (aset string (+ datestart i) (aref time i))))
-      (tar-dotimes (i (length name)) (aset string (+ namestart i) (aref name i)))
-      (if (or (eq link-p 1) (eq link-p 2))
-         (progn
-           (tar-dotimes (i 3) (aset string (+ namestart 1 (length name) i) (aref (if (= link-p 1) "==>" "-->") i)))
-           (tar-dotimes (i (length link-name)) (aset string (+ namestart 5 (length name) i) (aref link-name i)))))
-      (put-text-property namestart (length string)
-                        'mouse-face 'highlight string)
-      string)))
-
+                 ((eq type 1) ?l)      ; link
+                 ((eq type 2) ?s)      ; symlink
+                 ((eq type 3) ?c)      ; char special
+                 ((eq type 4) ?b)      ; block special
+                 ((eq type 5) ?d)      ; directory
+                 ((eq type 6) ?p)      ; FIFO/pipe
+                 ((eq type 20) ?*)     ; directory listing
+                 ((eq type 29) ?M)     ; multivolume continuation
+                 ((eq type 35) ?S)     ; sparse
+                 ((eq type 38) ?V)     ; volume header
+                 (t ?\ )
+                 )
+           (tar-grind-file-mode mode)
+           (if (= 0 (length uname)) uid uname)
+           (if (= 0 (length gname)) gid gname)
+           size
+           (if tar-mode-show-date (tar-clip-time-string time) "")
+           (propertize name 'mouse-face 'highlight)
+           (if (or (eq type 1) (eq type 2))
+               (concat (if (= type 1) " ==> " " --> ") link-name)
+             ""))))
 
 (defun tar-summarize-buffer ()
   "Parse the contents of the tar file in the current buffer.
 Place a dired-like listing on the front;
 then narrow to it, so that only that listing
 is visible (and the real data of the buffer is hidden)."
+  (set-buffer-multibyte nil)
   (message "Parsing tar file...")
   (let* ((result '())
         (pos 1)
@@ -477,15 +426,20 @@ is visible (and the real data of the buffer is hidden)."
          (summaries nil))
       ;; Collect summary lines and insert them all at once since tar files
       ;; can be pretty big.
-      (tar-dolist (tar-desc (reverse tar-parse-info))
+      (dolist (tar-desc (reverse tar-parse-info))
        (setq summaries
              (cons (tar-header-block-summarize (tar-desc-tokens tar-desc))
                    (cons "\n"
                          summaries))))
-      (insert (apply 'concat summaries))
+      (let ((total-summaries (apply 'concat summaries)))
+       (if (multibyte-string-p total-summaries)
+           (set-buffer-multibyte t))
+       (insert total-summaries))
       (make-local-variable 'tar-header-offset)
       (setq tar-header-offset (point))
       (narrow-to-region 1 tar-header-offset)
+      (if enable-multibyte-characters
+         (setq tar-header-offset (position-bytes tar-header-offset)))
       (set-buffer-modified-p nil))))
 \f
 (defvar tar-mode-map nil "*Local keymap for Tar mode listings.")
@@ -509,7 +463,7 @@ is visible (and the real data of the buffer is hidden)."
   (define-key tar-mode-map [down] 'tar-next-line)
   (define-key tar-mode-map "o" 'tar-extract-other-window)
   (define-key tar-mode-map "p" 'tar-previous-line)
-  (define-key tar-mode-map "q" 'tar-quit)
+  (define-key tar-mode-map "q" 'quit-window)
   (define-key tar-mode-map "\^P" 'tar-previous-line)
   (define-key tar-mode-map [up] 'tar-previous-line)
   (define-key tar-mode-map "R" 'tar-rename-entry)
@@ -597,10 +551,13 @@ See also: variables `tar-update-datestamp' and `tar-anal-blocksize'.
   (setq require-final-newline nil) ; binary data, dude...
   (make-local-variable 'revert-buffer-function)
   (setq revert-buffer-function 'tar-mode-revert)
-  (make-local-variable 'enable-local-variables)
-  (setq enable-local-variables nil)
+  (make-local-variable 'local-enable-local-variables)
+  (setq local-enable-local-variables nil)
   (make-local-variable 'next-line-add-newlines)
   (setq next-line-add-newlines nil)
+  ;; Prevent loss of data when saving the file.
+  (make-local-variable 'file-precious-flag)
+  (setq file-precious-flag t)
   (setq major-mode 'tar-mode)
   (setq mode-name "Tar")
   (use-local-map tar-mode-map)
@@ -609,7 +566,7 @@ See also: variables `tar-update-datestamp' and `tar-anal-blocksize'.
   (setq write-contents-hooks '(tar-mode-write-file))
   (widen)
   (if (and (boundp 'tar-header-offset) tar-header-offset)
-      (narrow-to-region 1 tar-header-offset)
+      (narrow-to-region 1 (byte-to-position tar-header-offset))
       (tar-summarize-buffer)
       (tar-next-line 0))
   (run-hooks 'tar-mode-hook)
@@ -645,7 +602,7 @@ appear on disk when you save the tar-file's buffer."
 
 
 ;; Revert the buffer and recompute the dired-like listing.
-(defun tar-mode-revert (&optional no-autosave no-confirm)
+(defun tar-mode-revert (&optional no-auto-save no-confirm)
   (let ((revert-buffer-function nil)
        (old-offset tar-header-offset)
        success)
@@ -720,7 +677,10 @@ appear on disk when you save the tar-file's buffer."
         (start (+ (tar-desc-data-start descriptor) tar-header-offset -1))
         (end (+ start size)))
     (let* ((tar-buffer (current-buffer))
-          (tarname (file-name-nondirectory (buffer-file-name)))
+          (tar-buffer-multibyte enable-multibyte-characters)
+          (tarname (if (buffer-file-name)
+                       (file-name-nondirectory (buffer-file-name))
+                     (buffer-name)))
           (bufname (concat (file-name-nondirectory name)
                            " ("
                            tarname
@@ -735,10 +695,17 @@ appear on disk when you save the tar-file's buffer."
        (unwind-protect
            (progn
              (widen)
+             (set-buffer-multibyte nil)
              (save-excursion
                (set-buffer buffer)
-               (insert-buffer-substring tar-buffer start end)
-               (goto-char 0)
+               (if enable-multibyte-characters
+                   (progn
+                     ;; We must avoid unibyte->multibyte conversion.
+                     (set-buffer-multibyte nil)
+                     (insert-buffer-substring tar-buffer start end)
+                     (set-buffer-multibyte t))
+                 (insert-buffer-substring tar-buffer start end))
+               (goto-char (point-min))
                (setq buffer-file-name
                      ;; `:' is not allowed on Windows
                      (expand-file-name (concat tarname "!" name)))
@@ -748,17 +715,12 @@ appear on disk when you save the tar-file's buffer."
                ;; which determine the coding-system and decode the text.
                (let ((coding
                       (and set-auto-coding-function
-                           (funcall
-                            set-auto-coding-function
-                            (if (< (point-max) 4096)
-                                (buffer-substring-no-properties 1 (point-max))
-                              (concat
-                               (buffer-substring-no-properties 1  1025)
-                               (buffer-substring-no-properties
-                                (- (point-max) 3072) (point-max)))))))
+                           (save-excursion
+                             (funcall set-auto-coding-function
+                                      name (- (point-max) (point))))))
                      (multibyte enable-multibyte-characters)
                      (detected (detect-coding-region
-                                1 (min 16384 (point-max)))))
+                                1 (min 16384 (point-max)) t)))
                  (if coding
                      (or (numberp (coding-system-eol-type coding))
                          (setq coding (coding-system-change-eol-conversion
@@ -797,7 +759,8 @@ appear on disk when you save the tar-file's buffer."
                (set-buffer-modified-p nil)
                (tar-subfile-mode 1))
              (set-buffer tar-buffer))
-         (narrow-to-region 1 tar-header-offset)))
+         (narrow-to-region 1 tar-header-offset)
+         (set-buffer-multibyte tar-buffer-multibyte)))
       (if view-p
          (view-buffer buffer (and just-created 'kill-buffer))
        (if (eq other-window-p 'display)
@@ -854,6 +817,7 @@ the current tar-entry."
         (size (tar-header-size tokens))
         (start (+ (tar-desc-data-start descriptor) tar-header-offset -1))
         (end (+ start size))
+        (multibyte enable-multibyte-characters)
         (inhibit-file-name-handlers inhibit-file-name-handlers)
         (inhibit-file-name-operation inhibit-file-name-operation))
     (save-restriction
@@ -867,7 +831,11 @@ the current tar-entry."
                      (and (eq inhibit-file-name-operation 'write-region)
                           inhibit-file-name-handlers))
                inhibit-file-name-operation 'write-region))
-      (write-region start end to-file))
+      (unwind-protect
+         (let ((coding-system-for-write 'no-conversion))
+           (set-buffer-multibyte nil)
+           (write-region start end to-file nil nil nil t))
+       (set-buffer-multibyte multibyte)))
     (message "Copied tar entry %s to %s" name to-file)))
 
 (defun tar-flag-deleted (p &optional unflag)
@@ -875,7 +843,7 @@ the current tar-entry."
 With a prefix argument, mark that many files."
   (interactive "p")
   (beginning-of-line)
-  (tar-dotimes (i (if (< p 0) (- p) p))
+  (dotimes (i (if (< p 0) (- p) p))
     (if (tar-current-descriptor unflag) ; barf if we're not on an entry-line.
        (progn
          (delete-char 1)
@@ -896,6 +864,7 @@ With a prefix argument, un-mark that many files backward."
   (tar-flag-deleted (- p) t))
 
 
+;; When this function is called, it is sure that the buffer is unibyte.
 (defun tar-expunge-internal ()
   "Expunge the tar-entry specified by the current line."
   (let* ((descriptor (tar-current-descriptor))
@@ -933,7 +902,7 @@ With a prefix argument, un-mark that many files backward."
       ;; iteration over the files that remain, or only iterate up to
       ;; the next file to be deleted.
       (let ((data-length (- data-end data-start)))
-       (tar-dolist (desc following-descs)
+       (dolist (desc following-descs)
          (tar-setf (tar-desc-data-start desc)
                    (- (tar-desc-data-start desc) data-length))))
       ))
@@ -947,9 +916,11 @@ for this to be permanent."
   (interactive)
   (if (or noconfirm
          (y-or-n-p "Expunge files marked for deletion? "))
-      (let ((n 0))
+      (let ((n 0)
+           (multibyte enable-multibyte-characters))
+       (set-buffer-multibyte nil)
        (save-excursion
-         (goto-char 0)
+         (goto-char (point-min))
          (while (not (eobp))
            (if (looking-at "D")
                (progn (tar-expunge-internal)
@@ -957,8 +928,8 @@ for this to be permanent."
                (forward-line 1)))
          ;; after doing the deletions, add any padding that may be necessary.
          (tar-pad-to-blocksize)
-         (narrow-to-region 1 tar-header-offset)
-         )
+         (narrow-to-region 1 tar-header-offset))
+       (set-buffer-multibyte multibyte)
        (if (zerop n)
            (message "Nothing to expunge.")
            (message "%s files expunged.  Be sure to save this buffer." n)))))
@@ -968,8 +939,8 @@ for this to be permanent."
   "Remove the stars at the beginning of each line."
   (interactive)
   (save-excursion
-    (goto-char 1)
-    (while (< (point) tar-header-offset)
+    (goto-char (point-min))
+    (while (< (position-bytes (point)) tar-header-offset)
       (if (not (eq (following-char) ?\ ))
          (progn (delete-char 1) (insert " ")))
       (forward-line 1))))
@@ -1060,7 +1031,8 @@ for this to be permanent."
 
 (defun tar-alter-one-field (data-position new-data-string)
   (let* ((descriptor (tar-current-descriptor))
-        (tokens (tar-desc-tokens descriptor)))
+        (tokens (tar-desc-tokens descriptor))
+        (multibyte enable-multibyte-characters))
     (unwind-protect
        (save-excursion
          ;;
@@ -1070,9 +1042,10 @@ for this to be permanent."
            (forward-line 1)
            (delete-region p (point))
            (insert (tar-header-block-summarize tokens) "\n")
-           (setq tar-header-offset (point-max)))
+           (setq tar-header-offset (position-bytes (point-max))))
          
          (widen)
+         (set-buffer-multibyte nil)
          (let* ((start (+ (tar-desc-data-start descriptor) tar-header-offset -513)))
            ;;
            ;; delete the old field and insert a new one.
@@ -1096,6 +1069,7 @@ for this to be permanent."
                chk (tar-header-name tokens))
              )))
       (narrow-to-region 1 tar-header-offset)
+      (set-buffer-multibyte multibyte)
       (tar-next-line 0))))
 
 
@@ -1119,9 +1093,14 @@ to make your changes permanent."
     (error "This buffer doesn't have an index into its superior tar file!"))
   (save-excursion
   (let ((subfile (current-buffer))
-       (subfile-size (buffer-size))
+       (subfile-multibyte enable-multibyte-characters)
        (coding buffer-file-coding-system)
-       (descriptor tar-superior-descriptor))
+       (descriptor tar-superior-descriptor)
+       subfile-size)
+    ;; We must make the current buffer unibyte temporarily to avoid
+    ;; multibyte->unibyte conversion in `insert-buffer'.
+    (set-buffer-multibyte nil)
+    (setq subfile-size (buffer-size))
     (set-buffer tar-superior-buffer)
     (let* ((tokens (tar-desc-tokens descriptor))
           (start (tar-desc-data-start descriptor))
@@ -1129,12 +1108,14 @@ to make your changes permanent."
           (size (tar-header-size tokens))
           (size-pad (ash (ash (+ size 511) -9) 9))
           (head (memq descriptor tar-parse-info))
-          (following-descs (cdr head)))
+          (following-descs (cdr head))
+          (tar-buffer-multibyte enable-multibyte-characters))
       (if (not head)
        (error "Can't find this tar file entry in its parent tar file!"))
       (unwind-protect
        (save-excursion
        (widen)
+       (set-buffer-multibyte nil)
        ;; delete the old data...
        (let* ((data-start (+ start tar-header-offset -1))
               (data-end (+ data-start (ash (ash (+ size 511) -9) 9))))
@@ -1154,7 +1135,7 @@ to make your changes permanent."
            ;; update the data pointer of this and all following files...
            (tar-setf (tar-header-size tokens) subfile-size)
            (let ((difference (- subfile-size-pad size-pad)))
-             (tar-dolist (desc following-descs)
+             (dolist (desc following-descs)
                (tar-setf (tar-desc-data-start desc)
                          (+ (tar-desc-data-start desc) difference))))
            ;;
@@ -1186,7 +1167,7 @@ to make your changes permanent."
            ;; alter the descriptor-line...
            ;;
            (let ((position (- (length tar-parse-info) (length head))))
-             (goto-char 1)
+             (goto-char (point-min))
              (next-line position)
              (beginning-of-line)
              (let ((p (point))
@@ -1196,16 +1177,22 @@ to make your changes permanent."
                (setq after (point))
                ;; Insert the new text after the old, before deleting,
                ;; to preserve the window start.
-               (insert-before-markers (tar-header-block-summarize tokens t) "\n")
+               (let ((line (tar-header-block-summarize tokens t)))
+                 (if (multibyte-string-p line)
+                     (insert-before-markers (string-as-unibyte line) "\n")
+                   (insert-before-markers line "\n")))
                (delete-region p after)
                (setq tar-header-offset (marker-position m)))
              )))
        ;; after doing the insertion, add any final padding that may be necessary.
        (tar-pad-to-blocksize))
-       (narrow-to-region 1 tar-header-offset)))
+       (narrow-to-region 1 tar-header-offset)
+       (set-buffer-multibyte tar-buffer-multibyte)))
     (set-buffer-modified-p t)   ; mark the tar file as modified
     (tar-next-line 0)
     (set-buffer subfile)
+    ;; Restore the buffer multibyteness.
+    (set-buffer-multibyte subfile-multibyte)
     (set-buffer-modified-p nil) ; mark the tar subfile as unmodified
     (message "Saved into tar-buffer `%s'.  Be sure to save that buffer!"
             (buffer-name tar-superior-buffer))
@@ -1215,6 +1202,7 @@ to make your changes permanent."
     t)))
 
 
+;; When this function is called, it is sure that the buffer is unibyte.
 (defun tar-pad-to-blocksize ()
   "If we are being anal about tar file blocksizes, fix up the current buffer.
 Leaves the region wide."
@@ -1253,19 +1241,16 @@ Leaves the region wide."
        ;; (tar-pad-to-blocksize)
        ;; tar-header-offset turns out to be null for files fetched with W3,
        ;; at least.
-       (write-region (or tar-header-offset (point-min)) (point-max)
-                     buffer-file-name nil t)
+       (let ((coding-system-for-write 'no-conversion))
+         (write-region (or (byte-to-position tar-header-offset)
+                           (point-min))
+                       (point-max)
+                       buffer-file-name nil t))
        (tar-clear-modification-flags)
        (set-buffer-modified-p nil))
-    (narrow-to-region 1 tar-header-offset))
-  ;; return T because we've written the file.
+    (narrow-to-region 1 (byte-to-position tar-header-offset)))
+  ;; Return t because we've written the file.
   t)
-
-(defun tar-quit ()
-  "Kill the current tar buffer."
-  (interactive)
-  (kill-buffer nil))
-
 \f
 (provide 'tar-mode)