Correctly detect 'pax' format archives in append mode
authorjca <jca@openbsd.org>
Tue, 16 Apr 2024 18:52:43 +0000 (18:52 +0000)
committerjca <jca@openbsd.org>
Tue, 16 Apr 2024 18:52:43 +0000 (18:52 +0000)
We expect that existing pax archives start with a global or extended
header. If they don't, append operations will be done using ustar
format.

Fixes append mode on pax archives where pax(1) would bail out when
appending to pax archives, falsely detecting a mismatch.  Reading was
unaffected.  Reported by caspar@, ok caspar@ millert@

bin/pax/extern.h
bin/pax/options.c
bin/pax/tar.c

index 9730b8d..6e7031a 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: extern.h,v 1.62 2023/12/09 23:00:11 jca Exp $ */
+/*     $OpenBSD: extern.h,v 1.63 2024/04/16 18:52:43 jca Exp $ */
 /*     $NetBSD: extern.h,v 1.5 1996/03/26 23:54:16 mrg Exp $   */
 
 /*-
@@ -284,6 +284,7 @@ int tar_wr(ARCHD *);
 int ustar_id(char *, int);
 int ustar_rd(ARCHD *, char *);
 int ustar_wr(ARCHD *);
+int pax_id(char *, int);
 int pax_wr(ARCHD *);
 
 /*
index d8b1c09..2259b77 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: options.c,v 1.109 2024/04/15 22:07:08 caspar Exp $    */
+/*     $OpenBSD: options.c,v 1.110 2024/04/16 18:52:43 jca Exp $       */
 /*     $NetBSD: options.c,v 1.6 1996/03/26 23:54:18 mrg Exp $  */
 
 /*-
@@ -228,7 +228,7 @@ FSUB fsub[] = {
 /* 9: gzip, to detect failure to use -z */
        {NULL, 0, 4, 0, 0, 0, 0, gzip_id},
 /* 10: POSIX PAX */
-       {"pax", 5120, BLKMULT, 0, 1, BLKMULT, 0, ustar_id, no_op,
+       {"pax", 5120, BLKMULT, 0, 1, BLKMULT, 0, pax_id, no_op,
        ustar_rd, tar_endrd, no_op, pax_wr, tar_endwr, tar_trail,
        tar_opt},
 #endif
@@ -249,7 +249,7 @@ FSUB fsub[] = {
  * of archive we are dealing with. This helps to properly id archive formats
  * some formats may be subsets of others....
  */
-int ford[] = {5, 4, 9, 8, 7, 6, 3, 2, 1, 0, -1};
+int ford[] = {10, 5, 4, 9, 8, 7, 6, 3, 2, 1, 0, -1};
 
 /*
  * Do we have -C anywhere and what is it?
index cd64ec7..2e84004 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: tar.c,v 1.79 2024/01/20 17:34:50 jca Exp $    */
+/*     $OpenBSD: tar.c,v 1.80 2024/04/16 18:52:43 jca Exp $    */
 /*     $NetBSD: tar.c,v 1.5 1995/03/21 09:07:49 cgd Exp $      */
 
 /*-
@@ -1391,6 +1391,46 @@ ustar_wr(ARCHD *arcn)
        return wr_ustar_or_pax(arcn, 1);
 }
 
+/*
+ * pax_id()
+ *     determine if a block given to us is a valid pax header.
+ * Return:
+ *     0 if a pax header, -1 otherwise
+ */
+#ifndef SMALL
+int
+pax_id(char *blk, int size)
+{
+       HD_USTAR *hd;
+
+       if (size < BLKMULT)
+               return(-1);
+       hd = (HD_USTAR *)blk;
+
+       /*
+        * check for block of zero's first, a simple and fast test then check
+        * ustar magic cookie. We should use TMAGLEN, but some USTAR archive
+        * programs are fouled up and create archives missing the \0. Last we
+        * check the checksum and the type flag. If ok we have to assume it is
+        * a valid pax header.
+        */
+       if (hd->prefix[0] == '\0' && hd->name[0] == '\0')
+               return(-1);
+       if (strncmp(hd->magic, TMAGIC, TMAGLEN - 1) != 0)
+               return(-1);
+       if (asc_ul(hd->chksum,sizeof(hd->chksum),OCT) != tar_chksm(blk,BLKMULT))
+               return(-1);
+       /*
+        * It is valid for a pax formatted archive not to start with
+        * a global header nor with an extended header. In that case
+        * we'll fall back to ustar in append mode.
+        */
+       if (hd->typeflag == XHDRTYPE || hd->typeflag == GHDRTYPE)
+               return(0);
+       return (-1);
+}
+#endif
+
 /*
  * pax_wr()
  *     Write out a pax format archive.