Let tar extract files > 8G

Denys Vlasenko vda.linux at googlemail.com
Fri Dec 12 02:16:16 UTC 2008


Hi Ian!


On Thursday 11 December 2008 22:04, Ian Wienand wrote:
> 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 thought tar uses pax extensions for this...
but apparently not.

> I cribbed the base 256 converter from gnu tar sources

It shows that GNU sources were used as a base. ~180 bytes of code.

> +/* Extract a number encoded in base-256 */
> +static unsigned long long getBase256(char *str, int len)
> +{
> +#define LG_256 8

Non-8-bit-char machines are history.

> +       uintmax_t value;

1. Why unitmax_t if you plan to return unsigned long long anyway?
   ...which then will become off_t... 

2. Indentation by seven spaces is a novelty.

> +       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.

1. I didn't understand much.

2. File sizes can be negative?! wow.

> +          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));

How about (*str & 0x40) or (*str & (1 << 6)) for readability?

> +       uintmax_t topbits = (((uintmax_t) - signbit)
> +                            << (CHAR_BIT * sizeof (uintmax_t)
> +                                - LG_256 - (LG_256 - 2)));

Timing how fast I will grok it...

(0xffff...fffffc0 or 0) << (all bits - 14)
so,
0xff0000...00000 or 0

Took 5 minutes!

Let's look further. If signbit != 0, it's ALREADY something
bad (negative filesize!!!), if not, topbits is 0, why calculate it?

> +       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)

Especially sadistic method to check for overflows.

...
> -	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') ?

*tar.size == '\200'  is not  "top bit set".


Ok. Enough of pointless ranting for today :)

I reworked it so that it compiles into ~15 instructions on x86.
Also fixed a bug where we did not print lenghts correctly
in "tar tvf" output (were truncating them to unsigned ints),
tested and committed it to svn.

Thanks!
--
vda



More information about the busybox mailing list