Subject: bug#70987: 29.2; Zip nested in tar, members do not open

From: Eli Zaretskii <[email-masked]>
Date: Sun, 19 May 2024 16:22:37 +0300

> From: Benjamin Riefenstahl <[email-masked]>
> Date: Thu, 16 May 2024 18:26:19 +0200
> 
> Create a zip file wrapped in a tar file.  E.g. in a shell do:
> 
>   $ zip -j zipped /etc/passwd
>   $ tar cvzf tarred.tar.gz zipped.zip
> 
> In Emacs
> 
>   * C-x C-f tarred.tar.gz RET
>   * RET on zipped.zip
>   * RET on passwd
>   * Error: unzip:  cannot find or open tarred.tar.gz!./zipped.zip, ...

Does the patch below give good results?

diff --git a/lisp/arc-mode.el b/lisp/arc-mode.el
index 9a8dd66..bf9def6 100644
--- a/lisp/arc-mode.el
+++ b/lisp/arc-mode.el
@@ -563,6 +563,8 @@ archive-file-name-coding-system
 (defvar-local archive-files nil
   "Vector of `archive--file-desc' objects.")
 
+(defvar tar-archive-from-tar nil)
+
 ;; -------------------------------------------------------------------------
 ;;; Section: Support functions.
 
@@ -754,7 +756,8 @@ archive-mode
 	;; on local filesystem.  Treat such archives as remote.
 	(or archive-remote
 	    (setq archive-remote
-		  (or (string-match archive-remote-regexp (buffer-file-name))
+		  (or tar-archive-from-tar ; was included in a tar archive
+                      (string-match archive-remote-regexp (buffer-file-name))
 		      (string-match file-name-invalid-regexp
 				    (buffer-file-name)))))
 
@@ -920,6 +923,9 @@ archive-unique-fname
 If FNAME is something our underlying filesystem can't grok, or if another
 file by that name already exists in DIR, a unique new name is generated
 using `make-temp-file', and the generated name is returned."
+  (if (file-name-absolute-p fname)
+      ;; We need a file name relative to the filesystem root.
+      (setq fname (substring fname (1+ (string-search "/" fname)))))
   (let ((fullname (expand-file-name fname dir))
 	(alien (string-match file-name-invalid-regexp fname))
 	(tmpfile
@@ -1179,6 +1185,9 @@ archive-extract
          (buffer (get-buffer bufname))
          (just-created nil)
 	 (file-name-coding archive-file-name-coding-system))
+      (or archive-remote
+          (and (local-variable-p 'tar-archive-from-tar)
+               (setq archive-remote tar-archive-from-tar)))
       (if (and buffer
 	       (string= (buffer-file-name buffer) arcfilename))
           nil
diff --git a/lisp/tar-mode.el b/lisp/tar-mode.el
index 375191a..7278bee 100644
--- a/lisp/tar-mode.el
+++ b/lisp/tar-mode.el
@@ -135,6 +135,10 @@ tar-file-name-coding-system
 (put 'tar-superior-buffer 'permanent-local t)
 (put 'tar-superior-descriptor 'permanent-local t)
 
+(defvar tar-archive-from-tar nil
+  "Non-nil if an arc-mode archive file is a member of a tar archive.")
+(put tar-archive-from-tar 'permanent-local t)
+
 ;; The Tar data is made up of bytes and better manipulated as bytes
 ;; and can be very large, so insert/delete can be costly.  The summary we
 ;; want to display may contain non-ascii chars, of course, so we'd like it
@@ -1124,6 +1128,8 @@ tar-extract
                 default-directory))
         (set-buffer-modified-p nil)
         (normal-mode)                   ; pick a mode.
+        (when (derived-mode-p 'archive-mode)
+          (setq-local tar-archive-from-tar t))
         (setq-local tar-superior-buffer tar-buffer)
         (setq-local tar-superior-descriptor descriptor)
         (setq buffer-read-only read-only-p)