aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEli Zaretskii2019-12-30 18:17:03 +0200
committerEli Zaretskii2019-12-30 18:17:03 +0200
commit59f71d20eade09e6c2ef99fc4d9b99a161bff040 (patch)
tree6523dd1296d9dafdba473b05ea4f38f44d1cf41a
parente3ec84fd7d91c9fff756e28d14ce33f7a37ac19f (diff)
downloademacs-59f71d20eade09e6c2ef99fc4d9b99a161bff040.tar.gz
emacs-59f71d20eade09e6c2ef99fc4d9b99a161bff040.zip
Fix tar-mode reading the oldgnu Tar format
This makes sure an entry for a long file name will not accidentally appear as a directory, and thus its size will be disregarded, causing corrupted file headers for all the subsequent entries. The original problem happened because the long file name truncated to 99 bytes happened to end in a slash, which tar-mode takes to be the indication of a directory. * lisp/tar-mode.el (tar-header-block-tokenize): Accept an additional argument DISABLE-SLASH; if non-nil, don't set the link-type field of the descriptor to 5 (meaning a directory) just because the name ends in a slash. Use this argument when calling itself recursively, to read the entry of the file with a long name. Set the link-type to 5 if the long name ends in a slash. (Bug#38777)
-rw-r--r--lisp/tar-mode.el31
1 files changed, 25 insertions, 6 deletions
diff --git a/lisp/tar-mode.el b/lisp/tar-mode.el
index 569b01f978b..d3ad5830cf5 100644
--- a/lisp/tar-mode.el
+++ b/lisp/tar-mode.el
@@ -223,10 +223,14 @@ Preserve the modified states of the buffers and set `buffer-swapped-with'."
223 "Round S up to the next multiple of 512." 223 "Round S up to the next multiple of 512."
224 (ash (ash (+ s 511) -9) 9)) 224 (ash (ash (+ s 511) -9) 9))
225 225
226(defun tar-header-block-tokenize (pos coding) 226(defun tar-header-block-tokenize (pos coding &optional disable-slash)
227 "Return a `tar-header' structure. 227 "Return a `tar-header' structure.
228This is a list of name, mode, uid, gid, size, 228This is a list of name, mode, uid, gid, size,
229write-date, checksum, link-type, and link-name." 229write-date, checksum, link-type, and link-name.
230CODING is our best guess for decoding non-ASCII file names.
231DISABLE-SLASH, if non-nil, means don't decide an entry is a directory
232based on the trailing slash, only based on the \"link-type\" field
233of the file header. This is used for \"old GNU\" Tar format."
230 (if (> (+ pos 512) (point-max)) (error "Malformed Tar header")) 234 (if (> (+ pos 512) (point-max)) (error "Malformed Tar header"))
231 (cl-assert (zerop (mod (- pos (point-min)) 512))) 235 (cl-assert (zerop (mod (- pos (point-min)) 512)))
232 (cl-assert (not enable-multibyte-characters)) 236 (cl-assert (not enable-multibyte-characters))
@@ -272,7 +276,7 @@ write-date, checksum, link-type, and link-name."
272 (decode-coding-string name coding) 276 (decode-coding-string name coding)
273 linkname 277 linkname
274 (decode-coding-string linkname coding)) 278 (decode-coding-string linkname coding))
275 (if (and (null link-p) (string-match "/\\'" name)) 279 (if (and (null link-p) (null disable-slash) (string-match "/\\'" name))
276 (setq link-p 5)) ; directory 280 (setq link-p 5)) ; directory
277 281
278 (if (and (equal name "././@LongLink") 282 (if (and (equal name "././@LongLink")
@@ -283,12 +287,23 @@ write-date, checksum, link-type, and link-name."
283 ;; This is a GNU Tar long-file-name header. 287 ;; This is a GNU Tar long-file-name header.
284 (let* ((size (tar-parse-octal-integer 288 (let* ((size (tar-parse-octal-integer
285 string tar-size-offset tar-time-offset)) 289 string tar-size-offset tar-time-offset))
286 ;; -1 so as to strip the terminating 0 byte. 290 ;; The long name is in the next 512-byte block.
291 ;; We've already moved POS there, when we computed
292 ;; STRING above.
287 (name (decode-coding-string 293 (name (decode-coding-string
294 ;; -1 so as to strip the terminating 0 byte.
288 (buffer-substring pos (+ pos size -1)) coding)) 295 (buffer-substring pos (+ pos size -1)) coding))
296 ;; Tokenize the header of the _real_ file entry,
297 ;; which is further 512 bytes into the archive.
289 (descriptor (tar-header-block-tokenize 298 (descriptor (tar-header-block-tokenize
290 (+ pos (tar-roundup-512 size)) 299 (+ pos (tar-roundup-512 size)) coding
291 coding))) 300 ;; Don't intuit directories from
301 ;; the trailing slash, because the
302 ;; truncated name might by chance end
303 ;; in a slash.
304 'ignore-trailing-slash)))
305 ;; Fix the descriptor of the real file entry by using
306 ;; the information from the long name entry.
292 (cond 307 (cond
293 ((eq link-p (- ?L ?0)) ;GNUTYPE_LONGNAME. 308 ((eq link-p (- ?L ?0)) ;GNUTYPE_LONGNAME.
294 (setf (tar-header-name descriptor) name)) 309 (setf (tar-header-name descriptor) name))
@@ -296,6 +311,10 @@ write-date, checksum, link-type, and link-name."
296 (setf (tar-header-link-name descriptor) name)) 311 (setf (tar-header-link-name descriptor) name))
297 (t 312 (t
298 (message "Unrecognized GNU Tar @LongLink format"))) 313 (message "Unrecognized GNU Tar @LongLink format")))
314 ;; Fix the "link-type" attribute, based on the long name.
315 (if (and (null (tar-header-link-type descriptor))
316 (string-match "/\\'" name))
317 (setf (tar-header-link-type descriptor) 5)) ; directory
299 (setf (tar-header-header-start descriptor) 318 (setf (tar-header-header-start descriptor)
300 (copy-marker (- pos 512) t)) 319 (copy-marker (- pos 512) t))
301 descriptor) 320 descriptor)