diff options
| -rw-r--r-- | lisp/tar-mode.el | 31 |
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. |
| 228 | This is a list of name, mode, uid, gid, size, | 228 | This is a list of name, mode, uid, gid, size, |
| 229 | write-date, checksum, link-type, and link-name." | 229 | write-date, checksum, link-type, and link-name. |
| 230 | CODING is our best guess for decoding non-ASCII file names. | ||
| 231 | DISABLE-SLASH, if non-nil, means don't decide an entry is a directory | ||
| 232 | based on the trailing slash, only based on the \"link-type\" field | ||
| 233 | of 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) |