Let tar extract files > 8G

Ian Wienand ianw at vmware.com
Thu Dec 11 21:04:53 UTC 2008


Hi,

The 12 octal digits for size give each file a maximum size 8G.  GNU
tar encodes sizes larger than this with a base-256 encoding, and marks
the top bit of the size set to indicate this.

I cribbed the base 256 converter from gnu tar sources

Testing - extract a big file

$ ls -l
-rw-r--r-- 1 wienandi mts 10737428480 2008-12-11 12:42 bigfile.tar

wienandi at coopers:/tmp/big$ ./busybox tar xvf bigfile.tar
./bigfile

wienandi at coopers:/tmp/big$ ls -l
-rw-r--r-- 1 wienandi mts 10737418240 2008-12-11 12:33 bigfile
-rw-r--r-- 1 wienandi mts 10737428480 2008-12-11 12:42 bigfile.tar

Thanks,

-i

Index: archival/libunarchive/get_header_tar.c
===================================================================
--- archival/libunarchive/get_header_tar.c	(revision 24386)
+++ archival/libunarchive/get_header_tar.c	(working copy)
@@ -14,6 +14,37 @@
 #include "libbb.h"
 #include "unarchive.h"
 
+/* Extract a number encoded in base-256 */
+static unsigned long long getBase256(char *str, int len)
+{
+#define LG_256 8
+
+       uintmax_t value;
+       char *lim = str + len;
+       /* Parse base-256 output.  A nonnegative number N is
+          represented as (256**DIGS)/2 + N; a negative number -N is
+          represented as (256**DIGS) - N, i.e. as two's complement.
+          The representation guarantees that the leading bit is
+          always on, so that we don't confuse this format with the
+          others (assuming ASCII bytes of 8 bits or more).  */
+       int signbit = *str & (1 << (LG_256 - 2));
+       uintmax_t topbits = (((uintmax_t) - signbit)
+                            << (CHAR_BIT * sizeof (uintmax_t)
+                                - LG_256 - (LG_256 - 2)));
+       value = (*str++ & ((1 << (LG_256 - 2)) - 1)) - signbit;
+       for (;;)
+       {
+               value = (value << LG_256) + (unsigned char) *str++;
+               if (str == lim)
+                       break;
+               if (((value << LG_256 >> LG_256) | topbits) != value)
+               {
+                       bb_error_msg_and_die("Archive base-256 value is out of range");
+               }
+       }
+       return value;
+}
+
 /* NB: _DESTROYS_ str[len] character! */
 static unsigned long long getOctal(char *str, int len)
 {
@@ -234,7 +265,11 @@
 	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);
+
+	/* Really big (> 8 gig) files have the size encoded in base
+	 * 256.  The top bit being set tells us this ... */
+	file_header->size = (*tar.size == '\200') ?
+		getBase256(tar.size, sizeof(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 */



More information about the busybox mailing list