tar: improve OLDGNU compat, make old SUN compat configurable
authorDenis Vlasenko <vda.linux@googlemail.com>
Thu, 21 Jun 2007 12:41:59 +0000 (12:41 -0000)
committerDenis Vlasenko <vda.linux@googlemail.com>
Thu, 21 Jun 2007 12:41:59 +0000 (12:41 -0000)
archival/Config.in
archival/libunarchive/get_header_cpio.c
archival/libunarchive/get_header_tar.c

index 661c71ccf1aa12788cdde4477f5848d015a50eb6..49070da06fdff8acd665f8f5e3e62b31ad70e716 100644 (file)
@@ -205,6 +205,15 @@ config FEATURE_TAR_OLDGNU_COMPATIBILITY
          the old GNU format; help to kill this old format by
          repacking your ancient archives with the new format.
 
+config FEATURE_TAR_OLDSUN_COMPATIBILITY
+       bool "Enable untarring of tarballs with checksums produced by buggy Sun tar"
+       default N
+       depends on TAR
+       help
+         This option is required to unpack archives created by some old
+         version of Sun's tar (it was calculating checksum using signed arithmetic).
+         It is said to be fixed in newer Sun tar, but "old" tarballs still exist.
+
 config FEATURE_TAR_GNU_EXTENSIONS
        bool "Enable support for some GNU tar extensions"
        default y
index 724368be28e7aa808d01854a5ecd64be895a9d47..3f513551295ceab789f956292a7eef04e4f84c24 100644 (file)
@@ -16,8 +16,9 @@ typedef struct hardlinks_s {
 char get_header_cpio(archive_handle_t *archive_handle)
 {
        static hardlinks_t *saved_hardlinks = NULL;
-       static unsigned short pending_hardlinks = 0;
+       static unsigned pending_hardlinks = 0;
        static int inode;
+
        file_header_t *file_header = archive_handle->file_header;
        char cpio_header[110];
        int namesize;
index d42f4c2766750af9fe9479e94bcc94ebea9c2526..1a7a687cfb70cbc45680b42696d9e36370a14081 100644 (file)
@@ -36,7 +36,7 @@ static unsigned long long getOctal(char *str, int len)
        */
        str[len] = '\0';
        v = strtoull(str, &str, 8);
-       if (*str)
+       if (*str && (!ENABLE_FEATURE_TAR_OLDGNU_COMPATIBILITY || *str != ' '))
                bb_error_msg_and_die("corrupted octal value in tar header");
        return v;
 }
@@ -45,7 +45,7 @@ static unsigned long long getOctal(char *str, int len)
 void BUG_tar_header_size(void);
 char get_header_tar(archive_handle_t *archive_handle)
 {
-       static int end;
+       static smallint end;
 
        file_header_t *file_header = archive_handle->file_header;
        struct {
@@ -69,7 +69,10 @@ char get_header_tar(archive_handle_t *archive_handle)
                char padding[12];   /* 500-512 */
        } tar;
        char *cp;
-       int i, sum_u, sum_s, sum;
+       int i, sum_u, sum;
+#if ENABLE_FEATURE_TAR_OLDSUN_COMPATIBILITY
+       int sum_s;
+#endif
        int parse_names;
 
        if (sizeof(tar) != 512)
@@ -115,20 +118,36 @@ char get_header_tar(archive_handle_t *archive_handle)
         * POSIX says that checksum is done on unsigned bytes, but
         * Sun and HP-UX gets it wrong... more details in
         * GNU tar source. */
-       sum_s = sum_u = ' ' * sizeof(tar.chksum);
+#if ENABLE_FEATURE_TAR_OLDSUN_COMPATIBILITY
+       sum_s = ' ' * sizeof(tar.chksum);
+#endif
+       sum_u = ' ' * sizeof(tar.chksum);
        for (i = 0; i < 148 ; i++) {
                sum_u += ((unsigned char*)&tar)[i];
+#if ENABLE_FEATURE_TAR_OLDSUN_COMPATIBILITY
                sum_s += ((signed char*)&tar)[i];
+#endif
        }
        for (i = 156; i < 512 ; i++) {
                sum_u += ((unsigned char*)&tar)[i];
+#if ENABLE_FEATURE_TAR_OLDSUN_COMPATIBILITY
                sum_s += ((signed char*)&tar)[i];
+#endif
+       }
+#if ENABLE_FEATURE_TAR_OLDGNU_COMPATIBILITY
+       sum = strtoul(tar.chksum, &cp, 8);
+       if ((*cp && *cp != ' ')
+        || (sum_u != sum USE_FEATURE_TAR_OLDSUN_COMPATIBILITY(&& sum_s != sum))
+       ) {
+               bb_error_msg_and_die("invalid tar header checksum");
        }
+#else
        /* This field does not need special treatment (getOctal) */
        sum = xstrtoul(tar.chksum, 8);
-       if (sum_u != sum && sum_s != sum) {
+       if (sum_u != sum USE_FEATURE_TAR_OLDSUN_COMPATIBILITY(&& sum_s != sum)) {
                bb_error_msg_and_die("invalid tar header checksum");
        }
+#endif
 
        /* 0 is reserved for high perf file, treat as normal file */
        if (!tar.typeflag) tar.typeflag = '0';