svn commit: trunk/busybox/archival: libunarchive

vda at busybox.net vda at busybox.net
Fri Dec 12 02:14:35 UTC 2008


Author: vda
Date: 2008-12-11 18:14:35 -0800 (Thu, 11 Dec 2008)
New Revision: 24387

Log:
header_verbose_list: show off_t size, not cast to (unsigned)
get_header_tar: support GNU tar's "base256" encoding

function                                             old     new   delta
get_header_tar                                      1536    1600     +64
header_verbose_list                                  242     257     +15



Modified:
   trunk/busybox/archival/libunarchive/get_header_tar.c
   trunk/busybox/archival/libunarchive/header_verbose_list.c
   trunk/busybox/archival/tar.c


Changeset:
Modified: trunk/busybox/archival/libunarchive/get_header_tar.c
===================================================================
--- trunk/busybox/archival/libunarchive/get_header_tar.c	2008-12-11 15:59:01 UTC (rev 24386)
+++ trunk/busybox/archival/libunarchive/get_header_tar.c	2008-12-12 02:14:35 UTC (rev 24387)
@@ -14,6 +14,74 @@
 #include "libbb.h"
 #include "unarchive.h"
 
+/*
+ * GNU tar uses "base-256 encoding" for very large numbers (>8 billion).
+ * Encoding is binary, with highest bit always set as a marker
+ * and sign in next-highest bit:
+ * 80 00 .. 00 - zero
+ * bf ff .. ff - largest positive number
+ * ff ff .. ff - minus 1
+ * c0 00 .. 00 - smallest negative number
+ *
+ * We expect it only in size field, where negative numbers don't make sense.
+ */
+static off_t getBase256_len12(const char *str)
+{
+	off_t value;
+	int len;
+
+	/* if (*str & 0x40) error; - caller prevents this */
+
+	if (sizeof(off_t) >= 12) {
+		/* Probably 128-bit (16 byte) off_t. Can be optimized. */
+		len = 12;
+		value = *str++ & 0x3f;
+		while (--len)
+			value = (value << 8) + (unsigned char) *str++;
+		return value;
+	}
+
+#ifdef CHECK_FOR_OVERFLOW
+	/* Can be optimized to eat 32-bit chunks */
+	char c = *str++ & 0x3f;
+	len = 12;
+	while (1) {
+		if (c)
+			bb_error_msg_and_die("overflow in base-256 encoded file size");
+		if (--len == sizeof(off_t)) 
+			break;
+		c = *str++;
+	}
+#else
+	str += (12 - sizeof(off_t));
+#endif
+
+/* Now str points to sizeof(off_t) least significant bytes.
+ *
+ * Example of tar file with 8914993153 (0x213600001) byte file.
+ * Field starts at offset 7c:
+ * 00070  30 30 30 00 30 30 30 30  30 30 30 00 80 00 00 00  |000.0000000.....|
+ * 00080  00 00 00 02 13 60 00 01  31 31 31 32 30 33 33 36  |.....`..11120336|
+ *
+ * str is at offset 80 or 84 now (64-bit or 32-bit off_t).
+ * We (ab)use the fact that value happens to be aligned,
+ * and fetch it in one go:
+ */
+	if (sizeof(off_t) == 8) {
+		value = *(off_t*)str;
+		value = SWAP_BE64(value);
+	} else if (sizeof(off_t) == 4) {
+		value = *(off_t*)str;
+		value = SWAP_BE32(value);
+	} else {
+		value = 0;
+		len = sizeof(off_t);
+		while (--len)
+			value = (value << 8) + (unsigned char) *str++;
+	}
+	return value;
+}
+
 /* NB: _DESTROYS_ str[len] character! */
 static unsigned long long getOctal(char *str, int len)
 {
@@ -234,7 +302,10 @@
 	file_header->gname = tar.gname[0] ? xstrndup(tar.gname, sizeof(tar.gname)) : NULL;
 #endif
 	file_header->mtime = GET_OCTAL(tar.mtime);
-	file_header->size = GET_OCTAL(tar.size);
+	/* Size field: handle GNU tar's "base256 encoding" */
+	file_header->size = (*tar.size & 0xc0) == 0x80 /* positive base256? */
+			? getBase256_len12(tar.size)
+			: GET_OCTAL(tar.size);
 	file_header->gid = GET_OCTAL(tar.gid);
 	file_header->uid = GET_OCTAL(tar.uid);
 	/* Set bits 0-11 of the files mode */

Modified: trunk/busybox/archival/libunarchive/header_verbose_list.c
===================================================================
--- trunk/busybox/archival/libunarchive/header_verbose_list.c	2008-12-11 15:59:01 UTC (rev 24386)
+++ trunk/busybox/archival/libunarchive/header_verbose_list.c	2008-12-12 02:14:35 UTC (rev 24387)
@@ -24,11 +24,11 @@
 		snprintf(gid, sizeof(gid), "%u", (unsigned)file_header->gid);
 		group = gid;
 	}
-	printf("%s %s/%s %9u %4u-%02u-%02u %02u:%02u:%02u %s",
+	printf("%s %s/%s %9"OFF_FMT"u %4u-%02u-%02u %02u:%02u:%02u %s",
 		bb_mode_string(file_header->mode),
 		user,
 		group,
-		(unsigned int) file_header->size,
+		file_header->size,
 		1900 + mtime->tm_year,
 		1 + mtime->tm_mon,
 		mtime->tm_mday,

Modified: trunk/busybox/archival/tar.c
===================================================================
--- trunk/busybox/archival/tar.c	2008-12-11 15:59:01 UTC (rev 24386)
+++ trunk/busybox/archival/tar.c	2008-12-12 02:14:35 UTC (rev 24387)
@@ -357,7 +357,8 @@
 	if (tbInfo->verboseFlag) {
 		FILE *vbFd = stdout;
 
-		if (tbInfo->tarFd == STDOUT_FILENO)	/* If the archive goes to stdout, verbose to stderr */
+		/* If archive goes to stdout, verbose goes to stderr */
+		if (tbInfo->tarFd == STDOUT_FILENO)
 			vbFd = stderr;
 		/* GNU "tar cvvf" prints "extended" listing a-la "ls -l" */
 		/* We don't have such excesses here: for us "v" == "vv" */




More information about the busybox-cvs mailing list